如何在模板 class 中特化模板方法?

How to specialize templated method in templated class?

我发现 C++ 模板非常难以理解。现在我正在尝试专门化模板化 class:

的模板化成员函数
template <bool COW>
class BaseReferencedObject {
public:
    BaseReferencedObject()                                 : refCount(0) {}
    BaseReferencedObject(const BaseReferencedObject<COW>&) : refCount(0) {}
    BaseReferencedObject<COW>& operator=(const BaseReferencedObject<COW>&) {return *this;}
    template <bool COW2> void increaseRefCount() const;
    void decreaseRefCount() const {refCount--;}
    int getRefCount() const {return refCount;}
private:
    mutable int refCount;
};

class BaseReferencedObject<false>;
class BaseReferencedObject<true >;

template<> void BaseReferencedObject<false>::increaseRefCount<false>() const {refCount++;}
template<> void BaseReferencedObject<true >::increaseRefCount<true >() const {refCount++;}

typedef BaseReferencedObject<false> ReferencedObject;
typedef BaseReferencedObject<true > SharedData      ;

但是,当我尝试编译这段代码时,我得到

SharedPtr.hh:31:62: error: expected initializer before ‘<’ token
 template<> void BaseReferencedObject<false>::increaseRefCount<false>() const {refCount++;}
                                                              ^

这是什么意思,我应该如何继续执行此操作?我试图通过谷歌搜索找到解决方案,但我找不到任何可以解决的问题有效。

顺便问一下,有人可以推荐任何好的资源来更好地理解 C++ 模板的核心工作原理吗?


关于我在这里尝试做的事情的简要说明:我还有第二个 class template <bool COW> class BaseSharedPointer,它是一个 class 引用对象的共享指针,这些对象继承自 ReferencedObject 或来自 SharedData。这个想法是只有使用 copy-on-write (COW) 的共享指针应该能够引用应该在写入时复制的对象(真-真组合),并且只有不使用的共享指针COW 应该能够引用不应在写入时复制的对象(假 - 假组合)。不应允许其他两种组合(真-假、假-真),因为混合使用 COW 的智能指针和不使用 COW 的智能指针被认为是一个坏主意。因此,我试图通过只为允许的组合实例化 increaseRefCount 方法的特化来使这些组合变得不可能,并且如果某些代码试图使用其中任何一个。

您需要添加另一个 template<> 来专门化成员函数

template<> template<> void BaseReferencedObject<false>::increaseRefCount<false>() const {refCount++;}
template<> template<> void BaseReferencedObject<true >::increaseRefCount<true >() const {refCount++;}

请注意,您只能针对周围 class 模板的特化来特化成员函数。

但是,您的代码示例还有另外两个方面不完全正确。首先,最好为 increaseRefCount 提供默认实现(这可以在 class 模板定义中完成)。二、你的两行

class BaseReferencedObject<false>;
class BaseReferencedObject<true >;

导致您在评论中提到的有点神秘的编译器错误。如果你 use clang instead of g++ 作为编译器,你会得到这些行的更清晰的错误:

error: template specialization requires 'template<>'

以及错误

error: incomplete type 'BaseReferencedObject' named in nested name specifier

用于成员函数专业化。原因是您没有定义 class 模板特化,而只是向前声明它们。但是,这不是必需的,因为您可以在不提供完整的 class 模板特化的情况下特化成员函数。

这是一个完整的代码示例:

#include <iostream>

template <bool COW>
class BaseReferencedObject {
public:
    BaseReferencedObject()                                 : refCount(0) {}
    BaseReferencedObject(const BaseReferencedObject<COW>&) : refCount(0) {}
    BaseReferencedObject<COW>& operator=(const BaseReferencedObject<COW>&) {return *this;}
    template <bool COW2> void increaseRefCount() const { std::cout << "DEFAULT\n"; refCount++; }
    void decreaseRefCount() const {refCount--;}
    int getRefCount() const {return refCount;}
private:
    mutable int refCount;
};

template<> template<> void BaseReferencedObject<false>::increaseRefCount<false>() const { std::cout << "FALSE\n"; refCount++;}
template<> template<> void BaseReferencedObject<true >::increaseRefCount<true >() const { std::cout << "TRUE \n"; refCount++;}

typedef BaseReferencedObject<false> ReferencedObject;
typedef BaseReferencedObject<true > SharedData      ;

int main()
{
    BaseReferencedObject<false> b0;
    BaseReferencedObject<true > b1;

    b0.increaseRefCount<false>();
    b0.increaseRefCount<true>();
    b1.increaseRefCount<true >();
    b1.increaseRefCount<false>();
}

Live Example.

更新:如果不想要默认实现,可以显式删除其他组合

template<> template<> void BaseReferencedObject<false>::increaseRefCount<true>() const = delete;
template<> template<> void BaseReferencedObject<true >::increaseRefCount<false >() const = delete;

当您只遗漏默认实现时,这会产生编译器错误而不是链接器错误。