CRTP 没有编译时检查吗?
Has CRTP no compile time check?
我试图使用奇怪的重复模板模式实现静态多态性,当我注意到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;
}
程序的输出为:
A
B
A
为什么演员表工作没有错误?如何进行编译时检查来帮助解决此类错误?
在 CRTP 中解决此问题的常用方法是使基类具有私有构造函数,并将模板中的类型声明为友元:
template< typename T >
struct CRTP
{
void do_it( )
{
static_cast< T& >( *this ).execute( );
}
friend T;
private:
CRTP() {};
};
在你的例子中,当你不小心从CRTP<A>
继承C
时,C
不是CRTP<A>
的朋友,它不能调用它的构造函数,而且由于C
必须构造它的所有基来构造自己,你永远无法构造一个C
。唯一的缺点是这不会阻止编译本身;要得到编译器错误,你必须尝试实际构造一个C
,或者为它编写一个用户定义的构造函数。在实践中,这仍然足够好,这样您就不必像其他解决方案所建议的那样在每个派生中添加保护代码(恕我直言,这违背了整个目的)。
活生生的例子:http://coliru.stacked-crooked.com/a/38f50494a12dbb54。
注意:根据我的经验,CRTP 的构造函数必须是"用户声明的",这意味着您不能使用=default
。否则,在这种情况下,您可以获得聚合初始化,这将不尊重private
。同样,如果您试图保留trivially_constructible
特征(这不是一个非常重要的特征),这可能是一个问题,但通常这无关紧要。
Q1为什么强制转换工作没有错误?
当没有任何明智的事情适用时...
从 https://timsong-cpp.github.io/cppwp/n3337/expr.static.cast#2:
否则,转换的结果是未定义的。
Q2如何进行编译时检查以帮助解决此类错误?
我无法找到可用于CRTP
的方法。我能想到的最好的方法是在派生类中添加static_assert
。
例如,如果将C
更改为:
struct C : CRTP< A > // it should be CRTP< C >, but typo mistake
{
static_assert(std::is_base_of<CRTP<C>, C>::value, "");
void execute( )
{
cout << "C" << endl;
}
};
您将在编译时看到错误。
您可以将其简化为
struct C : CRTP< A > // it should be CRTP< C >, but typo mistake
{
using ThisType = C;
static_assert(std::is_base_of<CRTP<ThisType>, ThisType>::value, "");
void execute( )
{
cout << "C" << endl;
}
};
需要在每个派生类型中添加类似的代码。它不优雅,但它会起作用。
PS我不建议使用建议的解决方案。我认为考虑到偶尔的人为错误,开销太大了。
- C++:编译时检查匹配的函数调用对?
- 在编译时检查字符串文本的长度
- 编译时检查 #pragma 包的使用情况
- 检查编译时是否存在静态函数
- 编译时检查特征专用化是否具有唯一 ID
- MSVC 无法编译 SFINAE 检查
- 运行时检查失败 #0 用于运行时重新编译
- 如何在 clang 的自动会议中检查支持编译标志
- 检查该类在编译时C++中是否有任何基类
- 如何判断是否在编译时计算了"constexpr"(无需手动检查)
- 如何检查在编译时是否调用了模板化方法?
- 如何检查编译的代码是否使用了 SSE 和 AVX 指令?
- 用于检查编译时间常数的静态断言未传递给宏
- 我如何检查编译的时间
- GCC:检查编译为库还是可执行文件
- 检查编译的表达式是否包含所有隐式转换
- 如何检查编译库时使用的CUDA计算兼容性
- R:检查编译和加载标志的值
- 如何检查编译在哪个专门化模板中
- NetBeans c++的方式来检查编译用调试的代码