我有一个使用CRTP的非常简单的类:
template <typename DerivedType, void (DerivedType::*updateMethod)() = &DerivedType::update>
class UpdatableBase {};
class MyClass : private UpdatableBase<MyClass> {
public:
void update() {
}
};
int main() {
return 0;
}
使用g++ test.cpp -std=c++14
进行编译时,给出以下内容:
test.cpp:2:85: error: no member named 'update' in 'MyClass'
template <typename DerivedType, void (DerivedType::*updateMethod)() = &DerivedType::update>
~~~~~~~~~~~~~^
test.cpp:5:25: note: in instantiation of default argument for 'UpdatableBase<MyClass>' required here
class MyClass : private UpdatableBase<MyClass> {
^~~~~~~~~~~~~~~~~~~~~~
1 error generated.
为什么会说“ MyClass”中没有名为“ update”的成员?很明显是这样。
答案 0 :(得分:0)
这是CRTP的一个非常普遍的问题:编译器在读取派生的类定义之前先实例化基类定义。
解决方法是仅在基类成员定义中使用派生类的定义:
#include <type_traits>
template <typename DerivedType, class DelayedParameter = void>
class UpdatableBase {
public:
//definition of members of templates are instantiated when needed!
void update(){
if constexpr(std::is_same_v<DelayedParameter,void>)
static_cast<DerivedType>(this)->update();
else
(static_cast<DerivedType*>(this)->*DelayedParameter::value)();
}
};
class MyClassDelayedParameter;
class MyClass:public UpdatableBase<MyClass,MyClassDelayedParameter>
//the compiler only instantiate the definition of the base class:
//it will only instantiate the DECLARATION of the base class members.
{
public:
void update();
};
//Here MyClass is defined so we can access its member.
struct MyClassDelayedParameter:
std::integral_constant<void(MyClass::*)(),&MyClass::update>
{};
//UpdatableBase<...>::update DEFINITION is instantiated here. At this point
//of instantiation, MyClass and MyClassDelayedParameter are defined.
int main() {
MyClass a;
UpdatableBase<MyClass,MyClassDelayedParameter>& b=a;
b.update();
return 0;
}