using intArray = int[];
int (&a) [4] = intArray{1, 2, 3, 4};
这是不允许的,因为将非const左值引用绑定到临时(rvalue)是非法的。 g ++ 4.9.1和clang 3.4.2都有错误;当a
const
合格
int const (&a) [4] = intArray{1, 2, 3, 4};
但是,当我这样做时
int &x = intArray{1, 2, 3, 4} [1];
两个编译器都编译好没有错误。为此开发标准(草案N3337),§5.2.1 Subscripting
说
1后缀表达式后跟方括号中的表达式是后缀表达式。其中一个表达式应具有“指向T的指针”类型,另一个表达式应具有未映射的枚举或整数类型。 结果是“T”类型的左值。类型“T”应该是完全定义的对象类型。表达E1 [E2]与*((E1)+(E2))
相同(根据定义)2 braced-init-list不能与内置的下标运算符一起使用。
如果我使用 1 ,那么我不明白为什么标准允许构造临时数组,因为在其中下标元素会给出一个左值,即我可以得到临时的左值与临时的原始概念相矛盾,只能绑定到左值参考或右值参考。
如果我选择 2 那么为什么编译器在我{1, 2, 3, 4}[1]
时不会抛出错误?
答案 0 :(得分:3)
问题1
关于不将临时工具绑定到左撇子的规则并不能提供铁定的安全性。它可以防止部分此类错误,但不是全部。我怀疑为了防止所有这些错误,需要将“临时性”的概念合并到类型系统中,就像const
一样。然后你可以“抛弃临时性”,如果你知道你不会保留参考的时间超过临时的生命周期。委员会已经决定我们的规则是值得的,可能他们也决定进一步努力是不值得的。
另一个例子,vector<int>(4)[0]
也会返回一个左值,即使operator[]
调用是临时的。因为这个标准不会禁止构造临时向量,我也没有看到它应该禁止临时数组。好的,所以vector
是用户定义的类型,而数组是内置的,但除此之外我认为情况类似。
如果您使用数组,尤其是临时数组,那么在某种程度上标准认为您得到了您应得的。它不会禁止临时数组,因为它可以从一个数据中获得一个左值。
我认为你有一个有效的一般观点。由于编译器具有必要的信息,下标可能可以在数组rvalues上更安全地定义。它可以计算一个rvalue,其值是相应数组元素的值。这可能会令人困惑或不方便,因为它与通常的下标表达不一致,但它会更安全:-)如果你写struct A {int a;}
,那么A().a
是一个右值,所以我不认为将该原则应用于数组是完全不可能的。当然,这将是一个突破性的变化。
问题2
您没有在braced-init-list上使用下标。您正在使用新式初始化器语法构造的临时表上使用它。也就是说,您的表达式解析(intArray{1, 2, 3, 4})[1]
,而不是intArray({1, 2, 3, 4}[1])
。