C ++-以成员函数作为模板参数从基类继承

时间:2019-05-05 17:14:35

标签: c++ c++14 crtp

我有一个使用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”的成员?很明显是这样。

1 个答案:

答案 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;
}

DEMO