如何在 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>
.
我不知道这是否是实现此目标的最佳方式。我觉得很恶心。
不过我想做更多。我想确保 B
是 SomeoneElse
本身。我该怎么做?
将Base
的构造函数(或析构函数)设为私有,然后将T
设为friend
。这样,唯一可以 construct/destruct a Base<T>
的是 T
.
如果您的 class 包含一些代码:
T* pT = 0;
Base *pB = pT;
如果 T
与 Base
的赋值不兼容,则会出现编译器错误。
这种检查在 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())
{}
};
我有以下基本模板 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>
.
我不知道这是否是实现此目标的最佳方式。我觉得很恶心。
不过我想做更多。我想确保 B
是 SomeoneElse
本身。我该怎么做?
将Base
的构造函数(或析构函数)设为私有,然后将T
设为friend
。这样,唯一可以 construct/destruct a Base<T>
的是 T
.
如果您的 class 包含一些代码:
T* pT = 0;
Base *pB = pT;
如果 T
与 Base
的赋值不兼容,则会出现编译器错误。
这种检查在 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())
{}
};