2017-01-09 58 views
3

这里是什么,我试图做一个最小版本: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(),但是,不。

与海湾合作委员会,例如,我得到以下错误:

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> { 

直观地(不理解有关模板实例的所有详细信息),这似乎是一个明智的错误。是否有另一种方法来实现相同的功能?

回答

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"

+0

谢谢!在写完这个问题几分钟后,我想出了一个类似的解决方案,但是由于我使用了'(T arg)'而不是'(T && arg)',所以你的方法会更好。 – ynimous

+0

我宁愿建议'template void common_with_arg(typename T :: Arg && arg){static_cast (this) - > impl_with_arg(std :: forward (arg)); ''。所以'arg'被限制为输入'D :: Arg',如示例代码所示。 cc @ynimous – skypjack