从基本的CRTP开始,核心概念是这个指针演员 -
#include "stdafx.h"
#include <iostream>
using namespace std;
template<class T>
class A
{
public:
void a0(){ static_cast<B*>(this)->a2(); }
void a2(){ cout << "a2 base" << endl; }
};
class B: public A<int>//<int>
{
public:
void a1(){ a0(); }
void a2(){ cout << "a2 derived" << endl; }
};
int _tmain(int argc, _TCHAR* argv[])
{
B b;
b.a1();
return 0;
}
如果A不是模板,为什么演员会失败? (MSVC:错误C2440:'static_cast':无法从'A * const'转换为'B *')
或者反过来说,如果是模板,为什么会这样呢?
class B;
class A
{
public:
void a0(){ static_cast<B*>(this)->a2(); }
void a2(){ cout << "a2 base" << endl; }
};
class B: public A
{
public:
void a1(){ a0(); }
void a2(){ cout << "a2 derived" << endl; }
};
可能与模板实例化的时间有关,但我对细节感到好奇。
答案 0 :(得分:0)
A
不是模板,则投射失败,因为static_cast
允许多种投射类型,并且因为它不知道A
和{{1}之间的关系它失败了演员。B
是非依赖类型名称,因此其行为应与非模板案例相同。但是,MSVC不正确地阻止检查,直到实例化它知道B
和A
之间的关系的类型。 (我尝试在g ++上编译,但确实按预期失败了。)另外请注意,您所做的并不是CRTP。在普通的CRTP中,您希望转换为B
而不是T*
,然后编译就好了。我还假设您的意思是B*
而不是class B: public A<B>
。
答案 1 :(得分:0)
这不是模板实例化的问题,而是一个定义顺序的问题。
在声明A类时,B类仍然是未知的,因此,您不能要求编译器验证static_cast或dynamic_cast。此时只有reinterpret_cast或C样式转换才有效。
但很容易修复:在声明B之后拒绝a0
的定义:
class B;
class A
{
public:
void a0();
void a2(){ cout << "a2 base" << endl; }
};
class B: public A
{
public:
void a1(){ a0(); }
void a2(){ cout << "a2 derived" << endl; }
};
void A::a0() {
static_cast<B*>(this)->a2();
}
这样,B已被声明并且static_cast被接受。