具有在语法树中的节点上定义的层次结构的表达式模板
Posted
技术标签:
【中文标题】具有在语法树中的节点上定义的层次结构的表达式模板【英文标题】:Expression templates with a hierarchy defined on the nodes in the syntax tree 【发布时间】:2019-05-09 11:56:05 【问题描述】:我找到了对表达式模板 here 的一个很好的解释。在文章中,我们找到了一个基本的算术表达式模板实现,如下(略作改编):
#include <iostream>
template <typename T>
struct plus
T operator()(const T a, const T b) const return a + b;
;
template <class ExprT>
struct exprTraits
typedef ExprT expr_type;
;
template <class ExprT1, class ExprT2, class BinOp>
class BinaryExpr
public:
BinaryExpr(ExprT1 e1, ExprT2 e2, BinOp op = BinOp()) : _expr1(e1), _expr2(e2), _op(op)
double eval() const return _op(_expr1.eval(), _expr2.eval());
private:
typename exprTraits<ExprT1>::expr_type _expr1;
typename exprTraits<ExprT2>::expr_type _expr2;
BinOp _op;
;
class Literal
public:
Literal(const double v) : _val(v)
double eval() const return _val;
private:
const double _val;
;
template <>
struct exprTraits<double>
typedef Literal expr_type;
;
class Variable
public:
Variable(double& v) : _val(v)
double eval() const return _val;
void operator+=(double x) _val += x;
private:
double& _val;
;
class SpecialVariable : public Variable
public:
SpecialVariable(double& v) : Variablev ;
double eval() const return -1000.0;
;
template <class ExprT1, class ExprT2>
BinaryExpr<ExprT1, ExprT2, plus<double>> operator+(ExprT1 e1, ExprT2 e2)
return BinaryExpr<ExprT1, ExprT2, plus<double>>(e1, e2);
共有三种类型的节点,Literal
、Variable
和SpecialVariable
,后者是后者的子类。这些特征允许在表达式中使用像 double
这样的内置类型,而不用 Literal
包装它们。
现在,假设我想在添加 double
和 Variable
并将其分配给 Variable
时做一些特别的事情。我将以下成员函数添加到Variable
:
void operator+=(BinaryExpr<double, Variable, plus<double>> expr) _val += 1000.0;
并编写一个小测试程序:
int main(int argc, char const* argv[])
double xd = 2.0, yd = 5.0;
Variable xxd;
SpecialVariable yyd;
x += 3.0 + y;
std::cout << "result : " << std::to_string(x.eval()) << "\n";
return 0;
然而,这仅适用于 Variable
s 而不是 SpecialVariable
s,即我得到以下编译器错误:
error: no match for ‘operator+=’ (operand types are ‘Variable’ and ‘BinaryExpr<double, SpecialVariable, plus<double> >’) x += 3.0 + y;
note: no known conversion for argument 1 from ‘BinaryExpr<double, SpecialVariable, plus<double> >’ to ‘BinaryExpr<double, Variable, plus<double> >’
这是完全合理的,因为如果模板类的模板参数有关系,则它们不一定有关系。
问题:我如何编写一个operator+=
来接受类型和可能是它们的子类型的表达式模板?我还没有看到解决这个特定问题的表达式模板教程。
【问题讨论】:
【参考方案1】:问题:我如何编写一个
operator+=
来接受带有类型及其子类型的表达式模板?
使用std::is_base_of
和 SFINAE
template <typename V>
std::enable_if_t<std::is_base_of_v<Variable, V>>
operator+= (BinaryExpr<double, V, plus<double>> expr)
_val += 1000.0;
上述代码在 C++17 中编译。
如果你使用的是 C++14,你必须使用
std::is_base_of<Variable, V>::value
而不是
std::is_base_of_v<Variable, V>
如果您使用的是 C++11,则必须使用
typename std::enable_if<std::is_base_of<Variable, V>::value>::type
而不是
std::enable_if_t<std::is_base_of_v<Variable, V>>
【讨论】:
当我使用您的 C++14 替代方案时,我得到以下error: dependent-name ‘std::is_base_of<Variable, V>::type’ is parsed as a non-type, but instantiation yields a type
和 note: say ‘typename std::is_base_of<Variable, V>::type’ if a type is meant
(使用 g++-7.4.0
和上述任一标准)
^ 没关系,我犯了一个错误(::type
vs ::value
在is_base_of
之后)以上是关于具有在语法树中的节点上定义的层次结构的表达式模板的主要内容,如果未能解决你的问题,请参考以下文章