我理解做类似以下的事情:
auto&& x = Matrix1() + Matrix2() + Matrix3();
std::cout << x(2,3) << std::endl;
Run Code Online (Sandbox Code Playgroud)
如果矩阵运算使用表达式模板(例如boost::ublas),将导致静默运行时错误.
是否有任何设计表达式模板的方法来防止编译器编译可能导致在运行时使用过期临时值的代码?
(我尝试解决这个问题没有成功,尝试就在这里)
表达式模板通常用作优化技术,以避免创建临时对象.它们推迟构造完整对象,直到模板用于赋值或初始化.这适用于字符串构建器,线性代数包等.
为了避免昂贵的副本,表达式模板类可以通过引用捕获更大的参数.我将以Qt QStringBuilder为例.
当引用超过表达式模板时,它可以工作:
QString foo = QString("A") + QString("B");
^^^^^^^^^^^^^^^^^^^^^^^^^^^
QStringBuilder<QConcatenable<QString>,
QConcatenable<QString>>
Run Code Online (Sandbox Code Playgroud)
表达式模板的转换和解析发生在赋值中.字符串临时表比作业更长.
唉,一旦推断出表达式模板类型而不是目标类型,我们就会遇到麻烦:
// WORKS
QString foo = []() -> QString { return QString("A") + QString("B"); }();
// FAILS
QString foo = []{ return QString("A") + QString("B"); }();
Run Code Online (Sandbox Code Playgroud)
并且:
auto foo = QString("A") + QString("B");
// foo holds references to strings that don't exist anymore
QString bar = foo; // oops
Run Code Online (Sandbox Code Playgroud)
一种解决方案是构建器保存对象的副本.由于QString这里的隐式共享,他们的复制很便宜,虽然比拿参考更昂贵.但是,假设参数是std::string:除非必要,否则你绝对不想复制它们.
是否有任何技术可用于检测完整的模板表达式是否未立即解析并且必须复制数据到目前为止只能引用?
注意:我不会询问表达式模板的任何特定现有实现.我只是QStringBuilder用作一个激励性的例子.这不是Qt问题,也不是特征问题等.标题就是这个问题.
给定一个表达式模板树,我想在处理它之前创建一个新的优化树.请考虑以下乘法运算示例:
a * b * c * d,
Run Code Online (Sandbox Code Playgroud)
由于operator*表达式树的从左到右的相关性,它产生:
(((a * b) * c) * d).
Run Code Online (Sandbox Code Playgroud)
我想生成一个转换的表达式树,其中乘法从右到左发生:
(a * (b * (c * d))).
Run Code Online (Sandbox Code Playgroud)
考虑二进制表达式类型:
template<typename Left, typename Right>
struct BinaryTimesExpr
{
BinaryTimesExpr() = default;
BinaryTimesExpr(const BinaryTimesExpr&) = default;
BinaryTimesExpr(BinaryTimesExpr&&) = default;
BinaryTimesExpr(Left&& l, Right&& r) : left(forward<Left>(l)), right(forward<Right>(r)) {}
BinaryTimesExpr& operator=(const BinaryTimesExpr&) = default;
BinaryTimesExpr& operator=(BinaryTimesExpr&&) = default;
Left left;
Right right;
};
Run Code Online (Sandbox Code Playgroud)
定义乘法运算符operator*:
template<typename Left, typename Right>
BinaryTimesExpr<Constify<Left>, Constify<Right>> operator*(Left&& l, Right&& r)
{ …Run Code Online (Sandbox Code Playgroud) 我们正在尝试在我的研究小组中实现一个新的C++代码来执行大型数值模拟(有限元,有限差分方法,拓扑优化等).该软件将被来自学术界和工业界的人们使用.
对于软件的密集线性代数部分,我们想要使用Eigen或Armadillo.我们希望围绕这些包构建一个包装器有两个原因:1.向用户而不是第三方API公开我们自己的API; 2.如果我们将来需要切换库.我理解原因2是一种非常昂贵的保险形式,但我们使用之前的模拟软件遇到了这种情况.
我遇到的有关包装第三方库的信息来自以下来源:
我的问题涉及构建这个包装类的最佳方法.理想情况下,薄层包装将是最好的,如:
template< typename T >
class my_vec {
private:
arma::Col< T > _arma_vec;
};
Run Code Online (Sandbox Code Playgroud)
或其与特征向量的等价物.
然后,我的班级将第三方库类称为:
my_vec::foo() { return _arma_vec.foo(); }
Run Code Online (Sandbox Code Playgroud)
我认为(我想对此进行确认)这个薄层的问题是我失去了从这些库已经实现的表达模板中获得的速度.例如,在Armadillo中,执行以下操作:
// Assuming these vectors were already populated.
a = b + c + d;
Run Code Online (Sandbox Code Playgroud)
变得像这样:
for ( std::size_t i = 0; i < a.size(); ++i ) {
a[i] = b[i] + c[i] + d[i];
}
Run Code Online (Sandbox Code Playgroud)
由于实现了表达式模板而没有创建任何临时值.同样的情况适用于Eigen.
就我而言,我失去表达模板的力量的原因是,虽然Armadillo或Eigen不会创造他们自己的临时工,但我的班级my_vec确实如此.避免这种情况的唯一方法是在表达模板周围构建一个薄层包装器.但是,在这一点上,这似乎违反了YAGNI原则.
这个相关的问题:
建议使用类似的东西:
my_vec a, b, c;
// ... populate vectors
a._arma_vec = …Run Code Online (Sandbox Code Playgroud) 在维基百科文章中,它提供了一些模板类.我想在实际代码中使用它.我怎样才能做到这一点?我发现几乎没有办法让我实例化一个Vec对象.
假设我有一些基于数组的代码可供表达式模板使用。例如,我operator[]重载了这些数组,也重载了算术运算符+等。
现在我想让 STL 算法any_of在这样的数组上运行。简单的方法是做
ExprArray<double, N> b, c; // init etc.
auto a = b + c; // for (auto i = 0; i < N; ++i) { a[i] = b[i] + c[i]; }
auto res = std::any_of(begin(a), end(a), SomePred{});
Run Code Online (Sandbox Code Playgroud)
当然,我想能够短路计算和具有经修饰的(范围为基础的)lib::any_of,做
// only compute b[i] + c[i] until SomePred is satisified
auto res = lib::any_of(b + c, SomePred{}); // write as explicit loop over b[i] + c[i]
Run Code Online (Sandbox Code Playgroud)
就其输入lib::any_of而言写入operator[]将完成这项工作,就像为重载的 …
由于某些奇怪的原因,我无法在这一段代码中获取模板参数以隐式转换为兼容类型.
#include <type_traits>
template <typename T, unsigned D>
struct vec;
template <>
struct vec<float, 2> {
typedef float scalar;
static constexpr unsigned dimension = 2;
float x, y;
float& operator[] (unsigned i) { return (&x)[i]; }
float const& operator[] (unsigned i) const { return (&x)[i]; }
};
template <typename L, typename R>
struct add;
template <typename L, typename R, unsigned D>
struct add<vec<L, D>, vec<R, D>> {
typedef vec<L, D> left_type;
typedef vec<R, D> right_type;
typedef vec<typename std::common_type<L, R>::type, D> …Run Code Online (Sandbox Code Playgroud) c++ templates expression-templates template-meta-programming c++11
QString可以连接Qt ,operator%它使用表达式模板来预先计算结果字符串的大小并优化几个链式调用operator+.有关详细信息,请参阅我的这个问题.
为什么没有std::basic_string采用类似的结构?这甚至是每个C++ 11允许的吗?我看到只有优点,显然ABI兼容性可以被库实现者在他们想要的时候打破(并且C++ 11提供了一个很好的理由,甚至对于libstdc ++).
我有一个CRTP基类如下:
template<typename Derived, size_t DIMS>
class Base {
public:
// here is I think where the problem is
inline const Derived& self() const {return *static_cast<const Derived*>(this);}
};
Run Code Online (Sandbox Code Playgroud)
然后将派生类定义为
template<typename T, size_t ... Rest>
class Derived: public Base<Derived<T,Rest...>,sizeof...(Rest)> {
public:
Derived() = default;
// This constructor binds any arbitrary expression to Derived
template<typename Expr, size_t DIMS>
inline Derived(const Base<Expr,DIMS>& src_) {
const Expr &src = src_.self();
print(src.rhs);
}
};
Run Code Online (Sandbox Code Playgroud)
考虑到我自己的运算符,我也有以下AddOperator也继承自base
template<typename TLhs, typename TRhs, size_t DIMS>
struct …Run Code Online (Sandbox Code Playgroud) 我正在使用计算内核的表达式模板构建代码.我的问题非常简短:为什么GNU G ++在包含+=以下示例的行中给出了段错误(4.9.1,使用-O3编译):
// Like this it crashes
auto expression = Ix_h( Ix(u) );
ut += expression;
Run Code Online (Sandbox Code Playgroud)
但是,当我输入等效代码时:
// But like this it does not
ut += Ix_h( Ix(u) );
Run Code Online (Sandbox Code Playgroud)
Clang和Intel都运行良好.
我在下面添加了完整的代码.抱歉长度,这是我可以创建的最短的例子:
struct Grid
{
Grid(const int itot, const int gc) :
itot(itot), gc(gc), istart(gc), iend(itot+gc), icells(itot+2*gc) {}
const int itot;
const int gc;
const int istart;
const int iend;
const int icells;
};
template<int loc, class Inner>
struct Interp
{
Interp(const Inner& inner) : inner_(inner) {}
const …Run Code Online (Sandbox Code Playgroud)