C++ 混合强类型基类与 CRTP 和返回值类型推导
Posted
技术标签:
【中文标题】C++ 混合强类型基类与 CRTP 和返回值类型推导【英文标题】:C++ mixing strongly typed base class with CRTP and return value type deduction 【发布时间】:2015-06-01 02:13:49 【问题描述】:我在类层次结构中存在一些概念问题,其中基类依赖于固定标量类型T
,但派生的 CRTP 类使用返回值类型推导。
例如,考虑以下类层次结构:
template<typename ... Args> struct VectorBase;
template<typename T>
struct VectorBase<T>
virtual T eval(int) const = 0;
auto operator[](int i) return this->eval(i);
;
template<typename T, typename Derived>
struct VectorBase<T, Derived> : public VectorBase<T>
virtual T eval(int i) const override final return this->operator[](i);
auto operator[](int i) const
return static_cast<Derived const&>(*this).operator[](i);
;
template<typename T>
struct Vector : public VectorBase<T, Vector<T> >
//just for code shortness,
//in reality there is a container which returns the corresponding elements
auto operator[](int i) const return T;
;
template<typename VectorType>
struct SomeTransformation : public VectorBase< /* ... what to write here generically? */ double, SomeTransformation<VectorType> >
VectorType const& v;
SomeTransformation(VectorType const& _v) : v(_v)
auto operator[](int i) const
//do something with vector v and return i-th element, e.g.
return v[i]*0.1;
;
DEMO
现在,给定一个值类型为int
的特定向量,比如说,可以应用SomeTransformation
并获得一个值类型为double
的向量。此外,我可以确定SomeTransformation
派生自VectorBase<double>
,因此,例如,我不能错误地将其分配给VectorBase<int>
-指针:
int main()
Vector<int> v;
std::cout<<typeid(decltype(v[0])).name()<<std::endl; //prints "i" for int
auto u = SomeTransformation<decltype(v)>(v);
std::cout<<typeid(decltype(u[0])).name()<<std::endl; //prints "d" for double
//works
std::unique_ptr<VectorBase<double> > ud = std::make_unique<SomeTransformation<decltype(v)> >(v);
//gives a compile-time error, which is good
//std::unique_ptr<VectorBase<int> > ui = std::make_unique<SomeTransformation<decltype(v)> >(v);
现在解决问题:在SomeTransformation
的标量类型参数中,我写了/* ... what to write here generically? */
,我真的很想写类似的东西
template<typename VectorType>
struct SomeTransformation :
public VectorBase<decltype(std::declval<SomeTransformation<VectorType> >().operator[](0)), SomeTransformation<VectorType> >
//...
;
为了自动推断转换的值类型并将该类型向下传播到基类。但是,这似乎不起作用,我认为这是因为基类是在派生类之前实例化的……所以我要推断其类型的类还不存在。
有没有办法在不破坏继承层次结构的情况下获得这种行为?
【问题讨论】:
您是否必须直接为SomeTransformation
使用继承层次结构?为什么不独立编写SomeTransformation
(实现一个概念),并提供一个继承自VectorBase<..>
的适配器类模板?
@dyp: 是的,这行得通,我也有过一次,在我意识到在我的情况下保持继承关系相当方便......否则我将不得不重新实现几个函数(如size(), update(...)
等),并在概念类中重新声明一些成员。
@dyp:我发布了一些替代方案的答案,但仍然存在一些问题,如果需要,请提前查看。
抱歉,我不太明白您的顾虑。你能举个例子吗?你能把基类分成一个接口(只有纯虚函数)和一个基类(有你想在派生类中使用的任何便利函数和成员)吗?
@dyp:我不确定我是否说清楚了:我的目标是在基类中使用推导出的返回类型作为模板参数,同时保持继承层次结构。
【参考方案1】:
我自己想出了一个可能的替代方案,并想提出来讨论。
例如,可以将类型参数T
也添加到派生类,然后使用虚拟类型来实例化此类一次。这样就可以推断出这样创建的类的返回类型,用于下一步实例化真正使用的类。
例子:
namespace detail
template<typename T, typename VectorType>
struct SomeTransformation :
public VectorBase<T, SomeTransformation<T, VectorType> >
//the same as above
;
struct DummyType
//make any type convertible to DummyType
template<typename T> DummyType(T const&)
;
template<typename VectorType>
using SomeTransformationValueType =
decltype(std::declval<detail::SomeTransformation<DummyType, VectorType> >().operator[](0));
template<typename VectorType>
using SomeTransformation =
typename detail::SomeTransformation<SomeTransformationValueType<VectorType>, VectorType>;
DEMO
【讨论】:
以上是关于C++ 混合强类型基类与 CRTP 和返回值类型推导的主要内容,如果未能解决你的问题,请参考以下文章