【问题标题】:C++ mixing strongly typed base class with CRTP and return value type deductionC++ 混合强类型基类与 CRTP 和返回值类型推导
【发布时间】: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&lt;double&gt;,因此,例如,我不能错误地将其分配给VectorBase&lt;int&gt;-指针:

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&lt;..&gt; 的适配器类模板?
  • @dyp: 是的,这行得通,我也有过一次,在我意识到在我的情况下保持继承关系相当方便......否则我将不得不重新实现几个函数(如size(), update(...) 等),并在概念类中重新声明一些成员。
  • @dyp:我发布了一些替代方案的答案,但仍然存在一些问题,如果需要,请提前查看。
  • 抱歉,我不太明白您的顾虑。你能举个例子吗?你能把基类分成一个接口(只有纯虚函数)和一个基类(有你想在派生类中使用的任何便利函数和成员)吗?
  • @dyp:我不确定我是否说清楚了:我的目标是在基类中使用推导出的返回类型作为模板参数,同时保持继承层次结构。

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


【解决方案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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-19
    • 1970-01-01
    相关资源
    最近更新 更多