为什么*this
类的derived<T>
仍为base<T>
类型?
我认为typename X
可以解决这个问题。
如果这看起来很难看,那么更好的方法是什么?
尝试失败:
template <typename T>
class Derived;
template <typename T, typename X>
class Base{
public:
T val;
X f(void){
return *this;
}
};
template <typename T>
class Derived: public Base<T, Derived<T> >{
};
int main(void){
Derived<int> B;
Derived<int> C = B.f();
}
错误:
test4.cpp(9): error: no suitable user-defined conversion from "Base<int, Derived<int>>" to "Derived<int>" exists
return *this;
^
detected during instantiation of "X Base<T, X>::f() [with T=int, X=Derived<int>]" at line 20
compilation aborted for test4.cpp (code 2)
答案 0 :(得分:3)
你可以用:
进行贬低X f(){ return static_cast<X&>(*this);}
答案 1 :(得分:2)
你有
X f(void){
return *this;
}
在此函数中,*this
的类型仍然是基类类型。没有从基本类型到X
的自动转换。
我无法建议一个干净的解决方案,因为此时X
可以是任何内容,不一定是Derived<T>
。
我可以使用:
template <typename T>
class Derived2 : public Base<T, double>
{
};
基类应如何处理?
f()
中使用的方法似乎是一个设计缺陷。
<强>更新强>
如果保证Derived
具有
template <typename T>
class Derived : public Base<T, Derived<T>>
{
};
然后,您可以使用:
X& f(void){
return static_cast<X&>(*this);
}
请注意,我已将返回类型从X
更改为X&
。它避免了每次调用函数时制作副本的成本。
答案 2 :(得分:2)
当编译器查看class Base<int, Derived<int>>
时,它没有理由相信实际存在从其继承的Derived<int>
。可以执行class Other : public Base<T, Derived<T>>{}
而class Base<int, Derived<int>>
到Derived<int>
的转换不正确,因此不允许自动转换。
如果你制定的规则说明第二个模板参数必须是继承该基础的派生类型(class Other
违反了),你可以绕过类型系统,但要确保规则不是侵犯。
答案 3 :(得分:1)
首先,我会修改Base
,使其只接受一个模板参数
这样,它完全匹配CRTP习语所显示的常见形式
实际上,在我看来,在这种情况下没有理由同时使用T
和Derived<T>
作为模板参数,因为后者已经包含前者和{{ 1}}是你想要遵守的模式:
T, Derived<T>
然后你可以使用@ Jarod42提到的促销来自底层:
template<typename>
class Base;
template <typename T, template<typename> typename X>
class Base<X<T>> {
// ...
};
template <typename T>
class Derived: public Base<Derived<T>>{
// ....
};
请注意,在这里你系统地制作了一个对象的副本,可能不是你想要的。
另一个选择是修改架构并使用协变返回类型(它遵循一个最小的工作示例):
X<T> f(void) {
return *static_cast<X<T>*>(this);
}
哪一个更适合你,主要取决于实际问题。