Cli*_*ton 9 c++ expression-templates c++11
据我所知,表达式模板将在C++ 11中基于范围而中断,因为for (auto x : expr)
它具有隐含性auto&& __range = expr
,这将导致悬空引用.
有没有办法创建表达式模板类,以便它们能够正确地使用基于范围的行为,或者至少抛出编译错误?
基本上,我想防止表达式模板正确编译但由于悬空引用而在运行时失败的可能性.我不介意在基于for的范围内使用表达式模板之前必须将表达式模板包装起来,只要在用户忘记包装表达式模板时没有静默运行时错误.
你通常无能为力.如果将表达式作为范围,则必须解析为在for
语句初始化后有效的内容.并且无法在编译时检测到任何特定类型的推断auto
.
最好使表达式系统更加基于移动,这样它就不必保存引用.与auto
试图存储对潜在死亡事物的引用相比,这将产生更安全的结果.如果复制不可移动类型会让您感到麻烦,那么就跟它一起生活吧.
我能想到几个选项,每个选项都有自己的丑陋之处。
一种明显的选择是使用指针(可能unique_ptr
)而不是引用。当然,为了使其工作,它要么需要从堆分配,要么需要自定义分配器。我认为如果有一个好的分配器,这种方法有一些优点。但话又说回来,运算符重载会变得很糟糕。
另一种方法是按值而不是 const 引用存储子表达式。这种方法的效率非常依赖于编译器,但由于您基本上是在处理一堆临时变量,所以我想现代编译器可以优化掉副本(或者至少是很多副本)。
最后一种方法允许您保持代码的相同结构,但强制用户计算表达式。它要求您只有一种可迭代类型,这是表达式的基础类型(例如std::vector<int>
)。任何表达式类都不应具有为其begin
定义end
的方法或函数,而应仅可转换为基础类型。这样,类似的代码for(auto x : expr)
将在编译时失败(因为expr
不可迭代),但编写for(auto x : static_cast<vector<int>>(expr))
可以工作,因为表达式已经被求值。
如果您希望使用基于范围的 for 循环来实现表达式模板操作,那么您可以在表达式模板类中提供私有或受保护begin
的方法。end
只需确保每个模板类可以访问其他模板类的begin
和方法即可。end
在这种情况下应该没问题,因为表达式模板是函数的参数,因此在该函数中编写循环时不必担心悬空引用。