表达式模板的模板化返回类型专门化

时间:2019-08-30 13:14:55

标签: c++ c++11 templates typetraits decltype

我正在处理几种表达式模板,我需要知道这些表达式的计算结果(例如double)。其中一些表达模板来自3rd party库。

我正在定义特征:

template <typename X1>
struct EvaluatedType

由于我不能使用本身就是模板的参数来专门化模板(例如EvaluatedType<MyExpression<T>>),所以我不专门化它,而是依靠可以重载的函数evaluate1(包括一些模板重载) ):

template <typename X1>
struct EvaluatedType
{
    using Type = decltype(evaluate1(std::declval<X1>()));
};

evaluate1不能是成员函数,因为它必须接受double之类的类型并支持第三方表达式模板类型。

我遇到的第一个问题是(MWE):

#include <type_traits>
#include <string>

std::string evaluate1(std::string a)
{return a;}

double evaluate1(double a)
{return a;}

template <typename X1>
struct EvaluatedType
{
    using Type = decltype(evaluate1(std::declval<X1>()));
};

int main()
{

EvaluatedType<double>::Type a;

a = 0.0;
(void) a+5.0;
}

此代码无法编译为:

error: invalid operands of types ‘void’ and ‘double’ to binary ‘operator+’
 (void) a+5.0;

a的类型为void,但我不明白为什么,因为evaluate1(double)的返回类型为double

我的另一个问题是,如果将evaluate1(double)的定义移到EvaluatedType的定义之后,它将无法创建EvaluatedType<double>::Type(它只能看到之前定义的字符串版本) 。这是有问题的,因为我希望其他开发人员能够为其表达式模板添加evaluate1的新版本,并能够在其他特征中使用EvaluatedType<Expr>来了解表达式将求值的类型。 / p>

有没有一种方法可以定义这种类型:

template <typename X1>
struct EvaluatedType;

EvaluatedType<X1>::Type为参数类型为evaluate1的调用X1的返回类型。

谢谢。

注意:我必须支持主要符合c ++ 11的gcc 4.8.5。

解决方案

从评论和答案来看,问题是:

  • (void)优先于+,因此来自void + double的错误
  • 如果未在EvaluatedType之前定义

由于我不能将ADL与double一起使用,因此必须在定义ResultType之前定义double的评估方法。对于其他评估方法,我必须确保它们在与参数相同的命名空间中定义。


template <typename X> typename std::enable_if<std::is_arithmetic<X>::value,double>::type evaluate(const X & x)
{
    return x;
}

template <typename X>
struct EvaluatedType
{
    using Type = decltype(evaluate(std::declval<X>()));
};

对于我们用于自动区分的表达式模板库,这些表达式的表达式从名称空间autodif中其自身类型(CRTP)的ScalarBase继承而来,其评估为xdouble(也继承了ScalarBase),其中包含double(值)+稀疏梯度向量。 :

namespace autodif
{
template < typename X > xdouble evaluate(const ScalarBase<X> & x)
{
    return x; // implicitly convert with xdouble template constructor
}

} // autodif

1 个答案:

答案 0 :(得分:2)

(void) a+5.0;

这是((void)a)+5.0;

你想要

(void)(a+5.0);
相关问题