C PIMPL成语,类模板和void模板参数

C++ Pimpl idiom, class templates, and void template parameter

本文关键字:void 参数 PIMPL 成语      更新时间:2023-10-16

我正在尝试将PIMPL成语与类模板一起使用,并在模板参数为void时遇到问题。这是我最新人为的例子:

#include <memory>
template<typename T> class Foo {
    class                 Impl;
    std::shared_ptr<Impl> pImpl;
public:
    Foo()
        : pImpl{new Impl()} {
    }
    void set(T value) {
        pImpl->set(value);
    }
    T get() {
        return pImpl->get();
    }
};
template<typename T> class Foo<T>::Impl {
    T value;
public:
    void set(T value) {
        this->value = value; // among other things
    }
    T get() {
        return value; // among other things
    }
};
template<> class Foo<void> {
    class                 Impl;
    std::shared_ptr<Impl> pImpl;
public:
    void set() {
        pImpl->set();
    }
    void get() {
        pImpl->get();
    }
};
class Foo<void>::Impl {
public:
    void set() {
        // do useful stuff
    }
    void get() {
        // do useful stuff
    }
};

在以下内容中编译上述结果:

$ g++ -dumpversion
4.8.5
void_int_template.cpp: In member function ‘void Foo<void>::set()’:
void_int_template.cpp:34:14: error: invalid use of incomplete type ‘class Foo<void>::Impl’
         pImpl->set();
              ^
void_int_template.cpp:30:27: error: forward declaration of ‘class Foo<void>::Impl’
     class                 Impl;
                           ^
void_int_template.cpp: In member function ‘void Foo<void>::get()’:
void_int_template.cpp:37:14: error: invalid use of incomplete type ‘class Foo<void>::Impl’
         pImpl->get();
              ^
void_int_template.cpp:30:27: error: forward declaration of ‘class Foo<void>::Impl’
     class                 Impl;
                           ^

我如何专业化类模板来容纳void模板参数?

完整的专业化提供了替代定义,这意味着您必须重新定义所有内容。

template<> class Foo<void> {
    class                 Impl;
    std::shared_ptr<Impl> pImpl;
public:
    Foo();
    void set();
    void get();
};
class Foo<void>::Impl {
public:
    void set() {
    }
    void get() {
    }
};
// these need to be inline iff it's in your header file
/* inline */ Foo<void>::Foo() : pImpl(new Impl) {}
/* inline */ void Foo<void>::set() { pImpl->set(); }
/* inline */ void Foo<void>::get() { pImpl->get(); }