nya*_*108 9 c++ static-cast static-polymorphism class-template
我试图使用奇怪的重复模板模式实现静态多态性,当我注意到static_cast<>,通常在编译时检查一个类型是否实际可以转换为另一个,在基类声明中错过了一个错误,允许代码向下转换基础与其中一个兄弟姐妹同课:
#include <iostream>
using namespace std;
template< typename T >
struct CRTP
{
void do_it( )
{
static_cast< T& >( *this ).execute( );
}
};
struct A : CRTP< A >
{
void execute( )
{
cout << "A" << endl;
}
};
struct B : CRTP< B >
{
void execute( )
{
cout << "B" << endl;
}
};
struct C : CRTP< A > // it should be CRTP< C >, but typo mistake
{
void execute( )
{
cout << "C" << endl;
}
};
int main( )
{
A a;
a.do_it( );
B b;
b.do_it( );
C c;
c.do_it( );
return 0;
}
Run Code Online (Sandbox Code Playgroud)
该计划的产出是:
A
B
A
Run Code Online (Sandbox Code Playgroud)
为什么演员表没有错误?如何进行编译时检查可以帮助解决此类错误?
在CRTP中解决此问题的常用方法是使基类具有私有构造函数,并将模板中的类型声明为朋友:
template< typename T >
struct CRTP
{
void do_it( )
{
static_cast< T& >( *this ).execute( );
}
friend T;
private:
CRTP() {};
};
Run Code Online (Sandbox Code Playgroud)
在你的例子中,当你不小心C继承CRTP<A>,因为C它不是它的朋友CRTP<A>,它不能调用它的构造函数,并且由于C必须构造它的所有基础来构造它自己,你永远不能构造一个C.唯一的缺点是,这并不妨碍汇编本身; 要获得编译器错误,您必须尝试实际构造一个C或为其编写用户定义的构造函数.在实践中,这仍然是足够好的,这样你就不必在每个派生中添加保护代码,正如其他解决方案所暗示的那样(恕我直言打败了整个目的).
实例:http://coliru.stacked-crooked.com/a/38f50494a12dbb54.
注意:根据我的经验,CRTP的构造函数必须是"用户声明",这意味着你不能使用=default.否则在这种情况下,您可以获得聚合初始化,这将不会受到尊重private.同样,如果你试图保持trivially_constructible特性(这不是一个非常重要的特征),这可能是一个问题,但通常它应该无关紧要.
| 归档时间: |
|
| 查看次数: |
453 次 |
| 最近记录: |