问题标签 [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.
c++14 - 具有 unique_ptr 和矩阵的持久表达式模板
我想使用表达式模板来创建一个跨语句持续存在的对象树。构建树最初涉及使用 Eigen 线性代数库进行一些计算。持久表达式模板将具有其他方法来通过以不同方式遍历树来计算其他数量(但我还没有)。
为了避免临时对象超出范围的问题,子表达式对象通过std::unique_ptr
. 随着表达式树的构建,指针应该向上传播,这样持有根对象的指针就可以确保所有对象都保持活动状态。由于 Eigen 创建的表达式模板包含对在语句末尾超出范围的临时对象的引用,因此情况变得复杂,因此必须在构建树时评估所有 Eigen 表达式。
val
下面是一个按比例缩小的实现,当类型是一个持有整数的对象时,它似乎可以工作,但是对于 Matrix 类型,它在构造output_xpr
对象时会崩溃。崩溃的原因似乎是 Eigen 的矩阵乘积表达式模板 ( Eigen::GeneralProduct
) 在使用之前就已损坏。但是,在崩溃发生之前,我自己的表达式对象或 of 的析构函数GeneralProduct
似乎都没有被调用,并且 valgrind 没有检测到任何无效的内存访问。
任何帮助都感激不尽!我也很欣赏关于我将移动构造函数与静态继承一起使用的评论,也许问题出在某个地方。
arrays - 分配给数组小节:我是否在这里分配了一个右值,如果是,我该如何解决?
为了让我的 Fortran 代码有一天更容易移植到 C++,我一直在研究一些表达式模板代码,以提供整个数组算术运算符以及从较长数组的指定部分复制和分配的能力。不幸的是,如果没有相当多的样板代码,我想不出一种方法来解决我的问题,我会尽可能地减少它们。
首先,我有一个非常简单的“C 风格数组结构”,它封装了一个指针和一个长度,适合在我的混合语言应用程序的 C、Fortran、C++ 和 Java 部分之间轻松地来回传递:
...对于所有本机类型,依此类推。然后,我根据Wikipedia 条目中关于该主题的建议方法定义了一些非常简单的表达式模板:
为了给我一种操作 C 风格向量内容的方法,我定义了一些模板:一个在预先存在的缓冲区中操作数据,另一个使用 std::vector 管理自己的内存:
呸!从这一点上,我可以做类似的事情
......他们很享受。现在,终于,我可以回答我的问题了。假设我想分配给一个数组小节,例如:
事实上,如果我在 Visual C++ 2013 中编译,这工作得很好,但在 gcc 中却不行。分配时编译失败,并显示以下消息:
现在,在尝试将临时对象分配给非 const 引用或尝试对 Rvalue 进行分配时,该错误消息似乎出现在文献中,并且 Visual C++ 被记录为相对于该规则较为松懈比 gcc (自然地, gcc 是符合标准的那个)。我可以理解为什么编译器可能会认为
作为一个右值,即使我已经向后弯腰试图阻止它。例如,我的 startingIndex::to() 方法勤奋地按值返回一个 nArray 对象,而不是按引用,如果我写
...然后这工作正常,编译器告诉我'test1'是一个'nArray<float_array_C>'(即一个float_array),就像它应该的那样。
所以,我的问题是:我实际上是否因为试图在这里分配一个右值而感到内疚?如果我是,我怎么能停止这样做,同时仍然能够以这种方式对子数组进行分配,或者至少以某种类似的可读方式。我真的希望这可以在 C++ 中以某种方式完成,否则我想我需要回到 Fortran 领域,写作
……从此过上幸福的生活。
更新
按照 Chris Dodd 的建议,我为进一步的 nArray 构造函数尝试了几种不同的形式并最终确定:
(暂时不需要支持自我分配检查)。gcc 编译器似乎克服了这个问题,但我得到的下一个错误是:
这至少是一条不同的信息(总是进步的标志),但它仍然暗示基本问题是分配给错误的参考。不幸的是,我不确定我应该在哪里寻找这个:我尝试让我的 operator+ 返回 VecSum<E1, T_C, E2, U_C> const & 而不是按值返回,但这完全没有区别. 现在我又被卡住了,所以我的下一个策略是在我的 Linux 分区中安装 clang,看看我是否会从中得到更有用的错误消息......
进一步更新:
Clang 不是特别有用。它只能说:
这并没有提供很多线索!
最终更新:
实际上,回想起来,解决方案是多么明显,我真的很尴尬。我需要做的就是给我的赋值运算符提供与普通移动赋值运算符完全相同的形式:
这当然是 Chris Dodd 一开始就建议的内容,并且在 Linux 和 Windows 上的 clang 和 gcc 中工作得非常好。
c++ - 模板方法匹配派生类型而不是基类
我有一组运算符需要重写以进行表达式模板。我希望基类型的所有派生类都与基类型匹配。然后其他的东西会被泛型类型捕获。不幸的是,泛型类型在基类型之前获取派生类型。为了让事情变得美好和混乱,一切都被大量模板化,包括一些 CRTP。让我试着给出一个更简单的代码版本:
现在,我不能使用任何新的 C++ 功能。(这是删除旧库的一些重构的一部分,因此我们可以升级到新的 cpp 标准。)不过,我可以使用 boost 的东西。我在想我的答案可能在于boost::enable_if
某些东西,但我所有的尝试都导致了死胡同。现在,请记住,目标是表达式模板,所以我不能为传入的数据做任何转换。是的......它太复杂了......我希望你有一些魔法。
问题的简短版本:
如何(1 * Derived) * Derived
匹配operator(T, Base)
第一个运算符,然后匹配operator(Base, Base)
第二个运算符?它目前匹配第一个罚款,然后第二个匹配一个 Base-generic 运算符,因为 T 不进行转换,因此比 Base 匹配得更好。
c++ - Boost.Proto:如何制作原始数组的表达式终端而不是 std::vector?
现在我正在尝试为向量表达式制作另一种迷你 EDSL(嵌入式领域特定语言)。实际上 Boost.Proto 用户指南已经提供了这样一个 EDSL 示例,“惰性向量”,其中向量表达式由std::vector<T>
. 但我必须改为使用原始数组的那些表达式。因为原始数组操作仍然是几个科学模拟程序的核心。
ArrayWrapper
因此,我在“惰性向量”代码中添加了一个数组包装类,并替换std::vector
为ArrayWrapper
. 此修改后的源代码已成功编译和链接。但是当我运行它时,核心被转储了。
这是源代码的修改版本:
我想我的数组包装类具有“惰性向量”程序的其余部分所需的所有必要成员函数。而且我认为这些成员函数的接口与std::vector
原始“惰性向量”程序使用的成员函数的接口相同。
可能我错过了一些重要的观点。但是如何解决这个问题?(我应该如何proto::terminal<T>
使用原始数组制作对象?)如果您能给我建议或提示,我将不胜感激。
c++ - 带有某些编译选项的 common_type 编译错误
上下文:我正在尝试编写表达式模板和 C++11 功能。附加的代码示例只是一个有趣的实验。在 ET 的这种变体中,每个表达式都跟踪自己的返回类型。common_type
然后编译器使用它来查找基于子表达式返回类型的其他表达式的返回类型。
问题:您可以在此处查看完整示例
我有一组函数可以动态计算返回类型,common_type
如下所示:
编译时
clang++ -std=c++11 -O3 -Wall -pedantic -Wextra main.cpp -lboost_iostreams -lz
一切正常。当使用编译时,clang++ -stdlib=libc++ -std=c++11 -O3 -Wall -pedantic -Wextra main.cpp -lcxxrt -ldl -lboost_iostreams -lz
我得到构建错误,其中非基元被传递到common_type
. (又名incompatible operand types ('Unary<int, int>' and 'int')
)
问题:是否匹配了错误的功能?即使在未使用的功能中,似乎common_type
也可以进行评估。有没有一种简单的方法来延迟common_type
两个终端表达式运算符的评估?
c++ - 如何将父引用添加到 Boost.Proto 表达式?
我想生成具有从子到父的“反向”引用的表达式树。有没有办法自定义 Proto 生成器或域,以便表达式包装器类(使用proto::extends<>
)包含对父表达式的引用?
这背后的目标是创建缓存评估结果的表达式树,以便可以有效地重新评估它们。我的策略是更新终端值,然后沿着树将父节点标记为“脏”,以便在评估根表达式时重新评估它们。
c++ - 算法可以与表达式模板兼容吗?
假设我有一些基于数组的代码可供表达式模板使用。例如,我operator[]
对这些数组进行了重载,并且还重载了算术运算符+
等。
现在我想让 STL 算法any_of
在这样的数组上运行。简单的方法是做
当然,我希望能够缩短计算并进行修改(基于范围lib::any_of
)
lib::any_of
在其输入上写入operator[]
将完成这项工作,就像为重载 . 所做的一样operator+
。但是,这需要对我可能在此类数组上运行的所有 STL 算法进行类似的重新实现。
问题:所以假设我想通过仅修改ExprArray iterators
. 是否可以修改ExprArray
迭代器operator*
并且operator++
以对基于范围的算法透明的方式进行?
因此,如果算法版本实际上是根据迭代器实现的,则循环for (auto it = first; it != last; ++it)
需要*it
知道它需要计算的事实b[i] + c[i]
,并且++it
必须知道它需要做的事实++i
。
c++ - C++ 表达式模板 - 为什么是基类?
我最近偶然发现了 C++ 中的表达式模板。关于它们的实现,我不太了解一件事,这就是为什么需要基类(与模板表达式相关的所有其他对象都以 CRTP 方式派生)。一个简单的例子,对向量(类型的对象Vec
,没有基类)进行加法和标量乘法:
上面的代码可以编译(除了指定的行),它可以正确地评估 main 函数中的简单表达式。如果表达式被分配给一个类型的对象Vec
并将它们的内容分配给一个Vec
对象,无论如何都会在这个过程中被破坏,为什么需要基类?(如本维基百科文章所示)
编辑:
我知道这段代码有点混乱和糟糕(在不必要的地方复制等),但我不打算使用这个特定的代码。这只是为了说明表达式模板在没有 CRTP 基类的情况下在此示例中工作 - 我试图弄清楚为什么这个基类是必要的。
c++ - 如何防止 QStringBuilder 超出其初始化范围
我一直在考虑更改一些代码以利用QStringBuilder
表达式模板来实现其声称的性能改进。不幸的是,这导致我的代码部分开始在某些地方崩溃,示例如下:
这种崩溃的原因是因为 lambda 表达式的返回类型被推断为QStringBuilder<QStringBuilder<QString,const char [3]>,QString>
在返回后尝试强制转换QString
以分配给accumulate
结果。这个转换崩溃是因为它试图使用对 lambda 范围内的对象的引用,这些对象现在已被销毁。可以通过显式指定 lambda 的返回类型来修复此崩溃,这样[](const QString& s, int i) -> QString
可以确保在退出闭包之前发生强制转换。
然而,QStringBuilder
在此处启用导致先前工作代码崩溃甚至没有发出警告的事实意味着我现在将避免在其他地方使用它,除非我可以保证这种情况不会再次发生。由于在这种情况下,RVO 可以防止发生任何复制,我认为禁用对象复制的常用技术不会起作用。有没有办法防止这种情况发生在QStringBuilder
或类似的表达式模板中,或者维护对自动变量的引用的对象总是不安全使用?
c++ - 表达式模板中的引用捕获可以与类型推导共存吗?
表达式模板通常用作一种优化技术,以避免创建临时对象。他们推迟构造完整的对象,直到模板用于赋值或初始化。这可用于字符串构建器、线性代数包等。
为了避免昂贵的副本,表达式模板类可以通过引用捕获更大的参数。我将以 QtQStringBuilder
为例。
当引用超过表达式模板时,它可以工作:
表达式模板的转换和解析发生在赋值时。字符串临时对象的寿命超过了分配。
唉,一旦推断出表达式模板类型而不是目标类型,我们就会遇到麻烦:
并且:
一种解决方案是让构建器保存对象的副本。由于QString
这里的 s 是隐式共享的,因此它们的复制很便宜,尽管仍然比持有引用更昂贵。但是,假设参数是std::string
:除非必要,否则您绝对不想复制它们。
有没有什么技术可以用来检测一个完整的模板表达式没有立即解析,并且必须复制数据到目前为止只持有一个引用?
注意:我不是在询问表达式模板的任何特定现有实现。我只QStringBuilder
用作一个激励的例子。这不是 Qt 问题,也不是特征问题等。标题就是问题,差不多。