关于c ++:奇怪的重复模板和模板参数依赖的子类化问题

Curiously Recurring Template and Template parameter dependent subclassing issues

我正在尝试使以下代码工作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
template < class __derived, class __object = typename __derived::Object >
struct Base {
    using Derived = __derived;
    using Object = __object;
    void function(Object o) { return Derived::function(s); }
}

//template < class __derived >
//struct Base {
//    using Derived = __derived;
//    using Object = typename Derived::Object;
//    void function(Object o) { return Derived::function(s); }
//}

template < class __object >
struct Derived : public Base< Derived< __Object > > {
    using Object = __object;
    void function(Object o) { ... }
}

我通过声明

1
Derived<double> obj;

问题是,编译器声称在推导Base类的第二个模板参数时,无法在Derived类中找到符号Object。同样的错误也由注释版本生成。

我试图在Eigen3代码的启发下做到这一点,特别是他们为了避免使用虚拟函数而使用的CRTP(奇怪的重复模板模式)。Eigen3实际上使用了一个traits类,但我不知道如何在目前的情况下模仿它。有人对此有什么建议吗?事先谢谢!


通常,如果您希望a从b继承,那么b除了声明之外,不能知道关于a的任何信息:

1
2
template < class __object >
struct Derived;

不幸的是,你想得到更多,所以你必须使用一个类型特征:

1
2
3
4
5
6
7
8
template<class __derived>
struct Base_traits {
    //using Object = ?????;
};
template<class __object>
struct Base_traits<Derived<__object>> {
    using Object = __object; //note, this also can't inspect B.
};

Base类可以随心所欲地检查Base_traits,因为特性根本不检查B

1
2
3
4
5
6
template < class __derived, class __object = typename Base_traits<__derived>::Object >
struct Base {
    using Derived = __derived;
    using Object = typename Base_traits<__derived>::Object;
    //or        
    using Object = __object;

不相关的前导双下划线不允许凡人使用,请使用一个前导下划线,后跟一个小写字母。或者,使用尾随下划线。

另外,语法

1
void function(Object o) { return Derived::function(s); }

不起作用,因为这个符号不能用于倒推,只能用于倒推。因此,你必须在this上使用static_cast。因为它有点难看,所以我把它放在一个函数后面:

1
2
3
4
5
    void foo(Object o) { self()->bar(o); }
private:
    __derived* self() {return static_cast<__derived*>(this);}
    const __derived* self() const {return static_cast<__derived*>(this);}
};

完整代码:http://coliru.stacked-crooked.com/a/81595b0fcd36ab93