CRTP:具有基于派生的参数的函数

时间:2017-01-09 15:12:24

标签: c++ crtp

这是我尝试做的最小版本:

template<typename D>
struct Base {

        void common() {
                // ... do something ...
                static_cast<D *>(this)->impl();
                // ... do something ...
        }

        void common_with_arg(typename D::Arg arg) {
                // ... do something ...
                static_cast<D *>(this)->impl_with_arg(arg);
                // ... do something more ...
        }
};

struct Derived : Base<Derived> {
        void impl() { }

        using Arg = int;
        void impl_with_arg(Arg arg) { }

};

Base::common()Derived::impl()正常工作(正如预期的那样)。 但是,Base::common_with_arg()Derived::impl_with_arg()不会。

例如,使用gcc,我收到以下错误:

1.cc: In instantiation of ‘struct Base<Derived>’:
1.cc:18:18:   required from here
1.cc:11:7: error: invalid use of incomplete type ‘struct Derived’
  void common_with_arg(typename D::Arg arg) {
       ^~~~~~~~~~~~~~~
1.cc:18:8: note: forward declaration of ‘struct Derived’
 struct Derived : Base<Derived> {

直观地(不了解有关模板实例化的所有细节),这似乎是一个明智的错误。还有另一种方法可以实现相同的功能吗?

1 个答案:

答案 0 :(得分:5)

void common_with_arg(typename D::Arg arg)
//                            ^^^^^^

您无法在此处访问D::Arg,因为需要Derived的定义。但是这个定义永远不可用,因为Base模板正在这里实例化......

struct Derived : Base<Derived> { 
//               ^^^^^^^^^^^^^

...其中Derived尚未完全定义。

一种可能的解决方法是将common_with_arg作为功能模板:

template <typename T>
void common_with_arg(T&& arg) {
        // ... do something ...
        static_cast<D *>(this)->impl_with_arg(std::forward<T>(arg));
        // ... do something more ...
}

example on wandbox

如果您确实需要Arg类型别名,请阅读以下问题:
"C++ static polymorphism (CRTP) and using typedefs from derived classes"