请考虑以下代码:
struct A {
int x;
};
int main() {
A a;
A b{a};
}
这个程序是否符合C ++ 11标准?在我的N3797副本中,它说
8.5.4列表初始化
[dcl.init.list]
3:类型
T
的对象或引用的列表初始化定义如下:
- 如果T
是聚合,则执行聚合初始化(8.5.1) - 否则,如果T
是std::initializer_list<E>
的专业化,... - 否则,如果T
是类类型,则考虑构造函数。枚举适用的构造函数,并使用重载决策选择最佳构造函数。如果转换任何类型需要缩小转换,则程序格式不正确 - 否则,如果初始化列表包含E
类型的单个元素且T
不是引用类型或与E
引用相关,则对象或引用初始化自那个元素;如果将元素转换为T
需要缩小转换,则程序格式不正确 - 否则,如果T
是引用类型,T
类型引用的临时值临时值是copy-list-initialized或direct-list-initialized,具体取决于初始化的类型。引用,引用与临时约束 - 否则,如果初始化列表没有元素,则对象进行值初始化 - 否则,该程序格式不正确。
示例的要点是,类型是聚合,但列表初始化应该调用复制构造函数。在gcc 4.8
和gcc 4.9
上,在C ++ 11标准下,它失败了:
main.cpp: In function ‘int main()’:
main.cpp:7:8: error: cannot convert ‘A’ to ‘int’ in initialization
A b{a};
^
并说A is not convertible to int
或类似,因为聚合初始化失败。在gcc 5.4
上,它在C ++ 11标准下工作正常。
在clang
上,clang-3.5
,3.6
会出现类似错误,并且会在clang-3.7
开始工作。
据我所知,它在C ++ 14标准中已经很好地形成了,并且在缺陷报告here中提到了它。
但是,我不明白为什么这被认为是标准中的缺陷。
标准写入时,
“如果X
,则执行foo初始化。否则,如果Y
,执行条形初始化,......否则,程序格式错误。”,
这不意味着如果X
成立,但无法执行foo初始化,那么我们应该检查Y
是否成立,然后尝试条形初始化?
这会使示例工作,因为当聚合初始化失败时,我们不匹配std::initializer_list
,我们匹配的下一个条件是“T
是类类型”,然后我们考虑构造
请注意,此 似乎是在此修改示例中的工作原理
struct A {
int x;
};
int main() {
A a;
const A & ref;
A b{ref};
}
所有相同的编译器都以与前面的示例相同的方式对待它,在C ++ 11和C ++ 14标准中。但似乎CWG缺陷记录中修改后的措辞不适用于此案例。它写着:
如果
T
是类类型且初始化列表具有类型cv T
的单个元素或从T
派生的类类型,则该对象将从该元素初始化。
http://open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html#1467
但是在第二个代码示例中,初始化列表在技术上包含const T &
。所以我不知道它是如何工作的,除非在聚合初始化失败后,我们应该尝试构造函数。
我错了吗?是否应该在聚合初始化失败后尝试构造函数?
以下是相关示例:
#include <iostream>
struct B {
int x;
operator int() const { return 2; }
};
int main() {
B b{1};
B c{b};
std::cout << c.x << std::endl;
}
在clang-3.6
,gcc-4.8
,gcc-4.9
,它打印2
,在clang-3.7
,gcc-5.0
打印1
假设我错了,并且在C ++ 11标准中,聚合的列表初始化应该是聚合初始化而不是其他任何东西,直到引入缺陷报告中的新措辞,这是否发生了这种情况即使我在较新的编译器上选择-std=c++11
?
答案 0 :(得分:4)
标准写入时,
&#34;如果执行X,foo初始化。否则,如果执行Y,条形初始化,......否则,程序格式不正确。&#34;,
这并不意味着如果X成立,但是无法执行foo初始化,那么我们应该检查Y是否成立,然后尝试条形初始化?
不,它没有。把它想象成实际的代码:
T *p = ...;
if(p)
{
p->Something();
}
else
{ ... }
p
不是NULL。这并不意味着它也是一个有效的指针。如果p
指向已销毁的对象,则p->Something()
失败将不会导致您跳至else
。你有机会在这种情况下保护电话。
所以你得到了未定义的行为。
同样如此。如果是X,那么做A.这并不意味着如果A失败会发生什么;它告诉你这样做。如果它无法完成......你就搞砸了。
答案 1 :(得分:3)
标准写入时,
&#34;如果
X
,则执行foo初始化。否则,如果Y
, 执行条形初始化,...这并不意味着如果
X
成立,但foo初始化不可能 执行,然后我们应检查Y
是否成立,然后尝试 棒初始化?
没有。如果X
成立,我们执行foo初始化。如果失败,程序就会形成错误。