C ++将强类型基类与CRTP混合并返回值类型推导

时间:2015-03-27 16:49:04

标签: c++ templates inheritance c++14 crtp

我在类层次结构中有一些概念性问题,其中Base类依赖于固定的标量类型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> >
{
     //...
};

为了自动推导转换的值类型并将此类型传播到基类。但是,这似乎不起作用,我认为是因为基类在派生类之前被实例化...所以我想推断出类型的类还不存在。

有没有办法在不破坏继承层次结构的情况下获取此行为

1 个答案:

答案 0 :(得分:0)

我自己想出了一个可能的替代方案,并希望将其提交讨论。

例如,可以向派生类添加类型参数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