问题标签 [expression-templates]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
0 回答
111 浏览

c++ - 使用表达式模板在矩阵中重载运算符

自过去几天以来,我一直在尝试找出表达式模板,但一直无法克服。我正在构建一个从 add 运算符开始的矩阵。我正在使用 c++14 构建。我的 matrix.h 看起来像这样:

Cpp 文件主函数看起来包含以下内容:

这显示以下错误:

我在网上搜索了很多,但我显然错过了一些东西。上面的代码取自https://riptutorial.com/cplusplus/example/19992/a-basic-example-illustrating-expression-templates。如果可以共享一些理解表达式模板的资源,我将不胜感激。

0 投票
1 回答
83 浏览

c++11 - 不匹配 operator+ ,也不匹配 c++ 中的向量构造调用

我正在尝试使用表达式模板来实现矩阵加法。我面临一些麻烦。这是我的矩阵代码:

使用 Matrix 类时出现两个错误。首先是矩阵不存在运算符+(我在测试中使用了int),即使我已经为'+'实现了运算符重载,另一个错误是在矩阵的第二个构造函数中。它说我对 mat 变量的构造函数的调用是无效的。但是向量确实有这样的构造函数

0 投票
2 回答
158 浏览

c++ - C++ 表达式模板模棱两可的运算符重载

我试图实现向量和矩阵表达式模板。两者都有运算符+重载,但我得到模棱两可的运算符错误。

如何在保留表达式模板的效果的同时重载矩阵和向量的运算符?

这是我的矩阵求和模板:

这是向量和模板:

以及导致错误的代码片段:

0 投票
1 回答
31 浏览

c++ - 具有在语法树中的节点上定义的层次结构的表达式模板

我在这里找到了对表达式模板的极好解释。在文章中,我们找到了一个基本的算术表达式模板实现,如下(稍作改编):

有三种类型的节点,LiteralVariableSpecialVariable是后者的子类。这些特征允许在表达式中使用内置类型double,而无需将它们包装Literal.

现在,假设我想在添加 adouble和 aVariable并将其分配给 a时做一些特别的事情Variable。我将以下成员函数添加到Variable

并编写一个小测试程序:

但是,这仅适用于Variables 而不是SpecialVariables,即我得到以下编译器错误:

这是完全合理的,因为如果模板类的模板参数有关系,则它们不一定有关系。

问题:我如何编写一个operator+=接受带有类型可能的子类型的表达式模板?我还没有看到解决这个特定问题的表达式模板教程。

0 投票
0 回答
96 浏览

c++ - 基于CRTP的文字与表达式模板的结合

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

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

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

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

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

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

所以我的问题是:

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

编辑

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

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

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

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

0 投票
1 回答
195 浏览

c++ - 为什么重载解决方案偏爱不受约束的模板功能而不是更具体的功能?

我有这个带有乘法的最小表达式模板库,即

和转置,即

我将介绍一些类型AB,其中后者是前者的子类:

然后,我可以按如下方式调用我的表达式模板库(带有用于打印到的重载std::cout):

这给了我输出:

到现在为止还挺好。现在假设我想要一个专门的处理方法来处理“类型变量的转置A<T>乘以A<T>某种类型的类型变量T”,就像我在main. 为此,我将介绍

我运行与main上面相同的函数,我仍然得到与上面相同的输出(unconstrained template)。这是意料之中的,因为transpose<B<double>>与 相比是完全不同的类型transpose<A<double>>,所以重载决议选择了operator*.

(当然,如果我将变量定义更改mainA而不是B,ADL 会调用专用函数并且输出是called: T operator*(const A<T> &one, const A<T> &two)and 6)。

我最近了解了 SFINAE,因此我预计对更具体的乘法运算符的以下更改会导致重载结果以选择专用函数:

即使使用 SFINAE'doperator*我仍然得到unconstrained template版本。怎么会?我应该进行哪些更改来调用更专业的模板函数?

0 投票
1 回答
139 浏览

c++ - 表达式模板中子表达式的嵌套

我们正在编写一个表达式模板库来处理具有稀疏梯度向量(一阶自动微分)的值的操作。我试图弄清楚如何根据表达式是否是临时的,通过引用或值来嵌套子表达式。

我们有一个 Scalar 类,它包含一个值和一个稀疏梯度向量。我们使用表达式模板(如 Eigen)来防止构建和分配过多的临时Scalar对象。因此,我们有Scalar继承自ScalarBase<Scalar>(CRTP) 的类。

类型对象之间的二元运算(例如 +、*)ScalarBase< Left >ScalarBase< Right >返回ScalarBinaryOp<Left, Right,BinaryOp>继承自 的对象ScalarBase< ScalarBinaryOp<Left, Right,BinaryOp> >

ScalarBinaryOp必须持有一个值或对类型为Leftand的操作数对象的引用Right。持有者的类型由RefTypeSelector< Expression >::Type.

目前,这始终是一个 const 引用。它目前适用于我们的测试用例,但持有对临时子表达式的引用似乎不正确或不安全。

显然,我们也不希望Scalar复制包含稀疏梯度向量的对象。如果xand yare Scalar,则表达式应包含对and的x+yconst 引用。但是,如果是来自to的函数,则应该持有对 的 const 引用和 的值。xyfScalarScalarx+f(y)xf(y)

因此,我想传递有关子表达式是否是临时的信息。我可以将其添加到表达式类型参数中:

ScalarBinaryOp< typename Left, typename Right, typename BinaryOp , bool LeftIsTemporary, bool RightIsTemporary >

RefTypeSelector

RefTypeSelector< Expression, ExpressionIsTemporary >::Type

但是我需要为每个二元运算符定义 4 种方法:

我希望能够通过完美的转发来实现这一点。但是我不知道如何在这里实现这一点。首先,我不能使用简单的“通用参考”,因为它们几乎可以匹配任何东西。我想可能将通用引用和 SFINAE 结合起来只允许某些参数类型,但我不确定这是要走的路。另外我想知道我是否可以对有关 Left 和 Right 最初是左值还是右值引用的信息进行编码,类型为 Left 和 Right 参数化ScalarBinaryOp而不是使用 2 个额外的布尔参数以及如何检索该信息。

我必须支持 gcc 4.8.5,它主要符合 c++11。

2019/08/15 更新:实施

0 投票
0 回答
112 浏览

c++ - 特征推导模板表达式类型

简而言之:我试图推断对矩阵执行一元运算的函数的返回值(这是一个表达式模板)。

在这种情况下,操作是计算协方差矩阵。

我在这里遵循了 Eigen 文档: https ://eigen.tuxfamily.org/dox/TopicCustomizing_NullaryExpr.html 并创建了一个将矩阵乘以 2 并返回其结果的最小示例。下面的代码片段显示了一个工作示例。对我来说,关键点是表达式不会被评估为中间结果,所以我不想返回类似Eigen::MatrixBase<Derived>.

像这样使用:

但是当我尝试对协方差矩阵做同样的事情时,它会推断出错误的类型ExpressionType(错误消息在底部给出)。

像这样称呼它:

给我以下错误信息:

我在这里想念什么?我正在尝试做的事情可能吗?在延迟评估(特定于协方差矩阵)的情况下想要这个是否合理?

这对我来说是一个练习(不是家庭作业),所以我真的很想知道是否有可能以这种方式推导出表达式模板的完整类型。

我当然也对这种方法的实用性感兴趣,但程度较小。

编辑:

由于这可能对某人有所帮助,因此这是一个工作版本。

像这样称呼它:

或者更简单的:

0 投票
0 回答
34 浏览

c++ - 带有可变参数模板的表达式模板运算符

使用可变参数模板,我们可以编写一个函数add,它接受任意数量的输入参数,然后返回一个Expression(延迟计算)。当调用特定索引时,此表达式一次性对所有输入向量的i所有元素求和。i

所有这些看起来都非常漂亮和整洁,但是是否可以重载实际的 operator,即编写以下内容:

不幸的是,第二个代码 usingv1 + v2 + v3导致编译错误:

  • 与 2019 年相比:Fatal Error C1001, An internal error has occurred in the compiler.
  • 海湾合作委员会 8.3.0:'Expression<Ts ...> operator+(const Ts& ...)' must have an argument of class or enumerated type

有没有办法使这项工作?

0 投票
1 回答
118 浏览

c++ - 简洁语法的 C++ 运算符修改/元编程策略

我现在正在学习 C++ 中的模板元编程和表达式模板,所以作为练习,我正在创建一个线性代数库来练习我正在学习的概念。

到目前为止,我的库为所有可以重载的二元运算符提供了一个完整的非成员运算符重载列表,并且具有易于扩展的相当流畅的界面。然而,我遇到的一个问题是矩阵运算通常有多种变化。例如,对于乘法,有一般矩阵乘法、点积、kroenecker 积、hadamard 积、叉积等等。

在 Matlab 中采用的一种巧妙的解决方法是用于 hadamard 乘法(和 .^、./ 等)的 .* 运算符。在这种情况下,Matlab 语言使用 . 运算符作为 * 运算符的修饰符。但是,我不知道 c++ 语言中有任何机制允许像这样修改运算符。这种行为是否有任何干净的解决方法?

以下是我已经想到的一些事情:

  • 运算符重载允许额外的模板参数。但是,我不完全确定如何在这种情况下利用这一点。例如,一些可能很好的东西(尽管在实践中,我不确定是否有有效的语法来实现这一点):
  • 使用 SFINAE/Concepts/if constexpr 和特征来修改二进制表达式类型或包装二进制表达式类型。句法:
  • 创建一个免费的二进制函数。可能的语法:
  • 使用成员函数。句法:

这些似乎都没有像 Matlab 那样优雅的语法:

是否有任何技术可以接近我可以考虑的运算符修饰符语法?或者任何使使用语法不那么冗长的一般技术?如果没有,是否有任何想法可以在未来的 C++ 版本中包含一些在这里可能有用的东西?