如何在 C++ 中强制使用奇怪的重复模板模式

How to force use of curiously recurring template pattern in C++

我有以下基本模板 class。

template<typename T>
class Base {
  public:
    void do_something() {
    }
};

它旨在用作奇怪的重复模板模式。它应该像class B : public Base<B>一样被继承。它必须 而不是 class B : public Base<SomeoneElse> 那样被继承。我想静态地执行这个要求。如果有人用错了,我预计会在编译阶段出错。

我正在做的是将 static_cast<T const&>(*this) 放入 do_something()。这样,继承模板的 class 就是或继承自作为模板参数提供的 class。对不起,令人困惑的表达。用简单的英语来说,它要求 B is or inheritance from SomeoneElse in class B : public Base<SomeoneElse>.

我不知道这是否是实现此目标的最佳方式。我觉得很恶心。

不过我想做更多。我想确保 BSomeoneElse 本身。我该怎么做?

Base的构造函数(或析构函数)设为私有,然后将T设为friend。这样,唯一可以 construct/destruct a Base<T> 的是 T.

如果您的 class 包含一些代码:

T* pT = 0;
Base *pB = pT;

如果 TBase 的赋值不兼容,则会出现编译器错误。

这种检查在 C++11 中进行了形式化,因此您不必手写并可以获得有用的错误消息:

#include <type_traits>

template<typename T>
class Base {

public:
    void do_something() 
    {
        static_assert(
            std::is_base_of<Base, T>::value,
            "T must be derived from Base");
    }
};

class B : public Base<B> { };

int main()
{
    B b;
    b.do_something();
}

至于确保 Base 的类型参数正是从它派生的 class,这在概念上似乎存在缺陷。作为基础 class 的 class 不能 "talk about" 继承它的类型。它可能通过多重继承被继承不止一次,或者根本没有。

到目前为止有两个很好的答案。这是另一个使用为某些方法(在本例中为构造函数)生成自定义访问键的习惯用法。它提供了正确使用的绝对保证,同时不会将基类中的私有方法暴露给派生类。

根据具体情况,它也可以用于控制对基础 class 中其他方法的访问。

template<class Derived>
struct Base
{
private:
    // make constructor private
    Base() = default;
protected:
    // This key is protected - so visible only to derived classes
    class creation_key{
        // declare as friend to the derived class
        friend Derived;
        // make constructor private - only the Derived may create a key
        creation_key() = default;
    };

    // allow derived class to construct me with a key
    Base(creation_key)
    {}

    // other methods available to the derived class go here

private:
    // the rest of this class is private, even to the derived class
    // (good encapsulation)
};

struct D1 : Base<D1>
{
    // provide the key
    D1()
    : Base<D1>(creation_key())
    {}

};