2012-03-01 56 views
9

这是我的理解表达式模板将在基于范围的基础上在C + + 11中断,因为for (auto x : expr)有一个隐含的auto&& __range = expr,这将导致悬空引用。表达式模板和基于范围的在C + + 11

有没有一种方法创建表达式模板类,以便他们要么基于不等的行为正确,或至少是抛出一个编译错误?

基本上,我想,以防止表达式模板可以正确编译,但在运行时失败,由于悬挂引用的可能性。如果用户忘记包装表达式模板,只要没有无声的运行时错误,我不介意在基于范围的应用中使用它们之前必须包装表达式模板。

+1

的'汽车&&'在基于范围的'for'循环可能真的变成是东西砸自己的脚很容易 - 我还没有真正理解到底是什么影响的范围类型,为什么(左值引用非常量:危险的,非引用:unproblematic,???)。 – Philipp 2012-03-05 23:24:52

+1

@菲利普:没有“范围类型”这样的东西。只有符合范围“概念”的类型。具体来说,有一对'begin/end'覆盖返回输入迭代器。 – 2012-03-07 03:16:51

+1

我想答案是确保表达式模板不符合范围“概念”,即他们没有“开始”和“结束”。 – Clinton 2012-03-07 06:35:43

回答

2

我可以想到几个选择,每个选项都有自己的丑陋。

一个显而易见的选择是使用指针(可能unique_ptr),而不是引用。当然,为了这个工作,它要么需要从堆中分配,要么需要自定义分配器。我认为用一个好的分配器,这种方法有一些优点。然后再次,操作员超载会变得讨厌。

另一种方法是按值而不是通过const引用存储子表达式。这种方法的效率非常依赖编译器,但由于你基本上处理了一堆临时对象,所以我想现代编译器可以优化副本(或者至少是很多副本)。

最后一种方法可以让你相同的结构保持你的代码,但强制用户来计算表达式。它要求你只有一个迭代类型,它是表达式的基本类型(比如说,std::vector<int>)。没有任何一个表达类应该为它们定义方法或函数,但应该只能转换为基础类型beginend。这样,代码for(auto x : expr)将在编译时失败(因为expr不可迭代),但编写for(auto x : static_cast<vector<int>>(expr))的工作原理是因为表达式已经过计算。

如果您希望使用基于范围的for循环来实现表达式模板操作,那么您可以在表达式模板类中提供专用或受保护的beginend方法。只要确保每个模板类都可以访问其他模板类的beginend方法。在这种情况下应该没问题,因为表达式模板是函数的一个参数,所以在函数中编写循环时,您不必担心悬挂引用。

6

对此,您通常无能为力。如果给出表达式作为范围,则它必须解析为在for语句的初始化后有效的内容。并且在编译时没有办法检测到由auto推导出的任何特定类型。

这将是更好地使你的表达系统更加举动为基础,所以它没有持有引用。这将产生更安全的结果auto比试图存储引用可能死了的东西。如果复制不可移动类型会给您带来麻烦,那么您只需要忍受它。

+2

这并不能解决问题。您的基于范围的for循环包含隐含的'auto && __ range = listOfInt;',如果'listOfInt'实际上是某个表达式模板类的值,则可能会导致问题。 – 2012-03-02 06:35:06

+0

@RichardSmith:的确如此,我认为在这种情况下,唯一能做的就是引入一个明确的演员或一个新的自动变量。 – Philipp 2012-03-07 21:53:07