我可以想到几个选择,每个选项都有自己的丑陋。
一个显而易见的选择是使用指针(可能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
方法。在这种情况下应该没问题,因为表达式模板是函数的一个参数,所以在函数中编写循环时,您不必担心悬挂引用。
的'汽车&&'在基于范围的'for'循环可能真的变成是东西砸自己的脚很容易 - 我还没有真正理解到底是什么影响的范围类型,为什么(左值引用非常量:危险的,非引用:unproblematic,???)。 – Philipp 2012-03-05 23:24:52
@菲利普:没有“范围类型”这样的东西。只有符合范围“概念”的类型。具体来说,有一对'begin/end'覆盖返回输入迭代器。 – 2012-03-07 03:16:51
我想答案是确保表达式模板不符合范围“概念”,即他们没有“开始”和“结束”。 – Clinton 2012-03-07 06:35:43