2

这是我用于表达式模板的基本实现,基于 CRTP,它允许我方便地组合多种类型的操作,而无需要求所有内容都成为表达式树。

template<typename E>
struct OpExpression
{
    auto eval(iter_type n) const
    {
        return static_cast<E const&>(*this).eval(n);
    }
};

template<typename T>
struct OpFrame : OpExpression<OpFrame<T>>
{
    T *ptr;
    OpFrame(T *ptr) : ptr{ ptr } {}

    T eval(iter_type n) const
    {
        return ptr[n];
    }
};


template<typename T>
struct OpLiteral : OpExpression<OpLiteral<T>>
{
    T value;
    OpLiteral<T>(T value) : value{ value } {}

    T eval(iter_type) const
    {
        return value;
    }
    operator T() const
    {
        return value;
    }
};

这是一个在两个值之间应用加法的类(以及一个运算符重载以使其美观):

template<typename E1, typename E2>
struct OpFrameAdd : OpExpression<OpFrameAdd<E1, E2>>
{
    OpFrameAdd(E1 const a, E2 const b) : a{ a }, b{ b } {}
    auto eval(iter_type n) const
    {
        return a.eval(n) + b.eval(n);
    }

protected:
    E1 const a;
    E2 const b;
};

template<typename E1, typename E2>
auto operator+(OpExpression<E1> const& a, OpExpression<E2> const& b)
{
    auto v = OpFrameAdd<E1, E2>(*static_cast<const E1*>(&a), *static_cast<const E2*>(&b));
    return v;
}

提供更多细节/背景;我有一个包含一堆值(可能是各种类型)的数组,还有一个算术表达式,定义了我想如何将该数组转换为另一个数组。然而,这种转换并不具体,所以我使用表达式树作为我可以传递给对象的东西,然后这些对象将以不同的方式处理它(即我必须等待评估它)。此外,我只想定义一次表达式。

我想知道,如果基于这种设计,我可以在我的表达式中引入文字(不强制转换为 an )吗?OpLiteral例如:

double arr[100]{ 0 };
OpFrame arr_t(arr);

// I can do this
auto ev1 = arr_t + arr_t + arr_t + OpLiteral(2.0);

// But I would prefer to do this
auto ev2 = arr_t + arr_t + arr_t + 2.0;

根据我的问题here,我知道2.0不会自动转换为正确的类型,但是该解决方案也与此设计不兼容(它会导致模棱两可的调用,或者在更大的表达式中,通过应用通用模板来混淆树而不是基于OpExpression<T>)。

我是如何尝试实施该解决方案的:

template<typename E1, typename T>
auto operator+(OpExpression<E1> const& a, T b)
{
    auto v = OpFrameAdd<E1, OpLiteral<T>>(*static_cast<const E1*>(&a), OpLiteral<T>(b));
    return v;
}
template<typename E2, typename T>
auto operator+(T a, OpExpression<E2> const& b)
{
    auto v = OpFrameAdd<OpLiteral<T>, E2>(OpLiteral<T>(a), *static_cast<const E2*>(&b));
    return v;
}

所以我的问题是:

是否可以扩展设计以以首选方式使用文字?如果不是,这是否只是我选择的模板/设计的限制?(转换OpLiteral为仍然比为每种类型和双方都创建一个新的运算符重载要容易得多)。更广泛地说,是否有已知的(不同的)设计来处理这个问题?我是否将此设计正确地应用于问题?

编辑

使用给定的设计,似乎不可能隐式接受和转换另一种类型。最终,问题似乎可以表述为:我想在 1)一个父类和另一个父类之间进行操作;2) 父类和任何其他对象;3)任何类和那个父类。显然,这本质上是有问题的。

例如,当我试图纠正上述尝试中的模棱两可的调用时,它反而导致子级之间的操作OpExpression成为OpLiteral. 这是因为它不会解析“正确”运算符(即应用具有两种参数类型的运算符OpExpression),而是选择具有更通用参数类型的运算符。

结论是,事实上,这只是设计的一个限制(并且有充分的理由)。

但是,假设我有一个我想在表达式中使用的所有文字类型的完整列表。如果我不想为每个模板创建单独的特化,我将如何修改重载运算符以使用它?我是否必须修改 的类OpExpression

4

0 回答 0