【发布时间】: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;
}
};
现在,给定一个值类型为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:我不确定我是否说清楚了:我的目标是在基类中使用推导出的返回类型作为模板参数,同时保持继承层次结构。
标签: c++ templates inheritance c++14 crtp