C ++ Pimpl习惯用法,类模板和void模板参数

时间:2017-06-02 20:04:22

标签: c++ c++11 templates

我正在尝试将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模板参数?

1 个答案:

答案 0 :(得分:1)

完全专业化提供了另一种定义,这意味着您必须重新定义所有内容。

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(); }