以下是在C++ 11中初始化变量的两种方法:
T a {something};
T a = {something};
Run Code Online (Sandbox Code Playgroud)
我在所有可以想到的场景中测试了这两个,但我没有发现差异.这个答案表明两者之间存在细微差别:
对于变量,我在这些
T t = { init };
或T t { init };
样式之间没有太多关注,我发现差异很小,最坏的情况只会导致有关滥用显式构造函数的有用的编译器消息.
那么,两者之间有什么区别吗?
GCC的实现破坏了std::initializer_list
返回full-expression结束时从函数返回的数组.它是否正确?
此程序中的两个测试用例都显示在使用值之前执行的析构函数:
#include <initializer_list>
#include <iostream>
struct noisydt {
~noisydt() { std::cout << "destroyed\n"; }
};
void receive( std::initializer_list< noisydt > il ) {
std::cout << "received\n";
}
std::initializer_list< noisydt > send() {
return { {}, {}, {} };
}
int main() {
receive( send() );
std::initializer_list< noisydt > && il = send();
receive( il );
}
Run Code Online (Sandbox Code Playgroud)
我认为该计划应该有效.但潜在的标准有点令人费解.
return语句初始化一个返回值对象,就像它被声明一样
std::initializer_list< noisydt > ret = { {},{},{} };
Run Code Online (Sandbox Code Playgroud)
这initializer_list
将从给定的初始化器系列初始化一个临时及其底层数组存储,然后initializer_list
从第一个初始化器初始化另一个.阵列的寿命是多少?"数组的生命周期与initializer_list
对象的生命周期相同." 但其中有两个; 哪一个是模棱两可的.8.5.4/6中的示例(如果它按照公布的方式工作)应该解决数组具有复制到对象的生命周期的歧义.然后返回值的数组也应该存在于调用函数中,并且应该可以通过将它绑定到命名引用来保留它.
对我而言,a pair
只是a的特例tuple
,但令我惊讶的是:
pair<int, int> p1(1, 2); // ok
tuple<int, int> t1(1, 2); // ok
pair<int, int> p2={1, 2}; // ok
tuple<int, int> t2={1, 2}; // compile error
Run Code Online (Sandbox Code Playgroud)
我们{}
用来初始化时为什么会有区别tuple
?
我试过甚至g++ -std=c++1y
但仍然有错误:
a.cc: In function 'int main()':
a.cc:9:29: error: converting to 'std::tuple<int, int>' from initializer list would use explicit constructor 'constexpr std::tuple<_T1, _T2>::tuple(_U1&&, _U2&&) [with _U1 = int; _U2 = int; <template-parameter-2-3> = void; _T1 = int; _T2 = int]'
tuple<int, int> t2={1, …
Run Code Online (Sandbox Code Playgroud) 你能猜出这个简单程序的输出吗?
\n#include <vector>\n#include <string>\n#include <exception>\n#include <iostream>\n\nint main()\n{\n try { \n struct X {\n explicit X(int) {}\n X(std::string) {} // Just to confuse you more...\n };\n std::vector<X>{"a", "b"};\n } catch (std::exception& x) {\n std::cerr << x.what();\n }\n}\n
Run Code Online (Sandbox Code Playgroud)\n好吧,我不能,这花了我一天的时间“研究”,然后才登陆这里,最终从一些复杂的现实生活代码中提取出来(到处都是类型别名,匿名。与非 POD 成员的联合以及手工 -精心策划的演员/导演等,只是为了营造氛围)。
\n而且……我还是看不出发生了什么!有人可以给一个温柔的提示吗?(希望只是一个盲点。我不再专业地从事 C++ 工作。)
\n注意:使用(最新的)MSVC/W4
和 GCC进行干净编译* -Wall
;两者的输出相同(语义上)。
* 即使没有“迷惑读者”这句话。我想我会做噩梦。
\n(请耐心等待我尽量不将所有内容拼写得更多 \xe2\x80\x94 毕竟,这确实是不言自明的,对吧?除了,对我来说完全相反......)
\n考虑一下这段C++ 11代码:
#include <iostream>
struct X
{
X(bool arg) { std::cout << arg << '\n'; }
};
int main()
{
double d = 7.0;
X x{d};
}
Run Code Online (Sandbox Code Playgroud)
在初始化过程中,从double到bool的转换范围正在缩小x
.根据我对标准的理解,这是错误的代码,我们应该看到一些诊断.
Visual C++ 2013发出错误:
error C2398: Element '1': conversion from 'double' to 'bool' requires a narrowing conversion
Run Code Online (Sandbox Code Playgroud)
但是,Clang 3.5.0和GCC 4.9.1都使用以下选项
-Wall -Wextra -std=c++11 -pedantic
Run Code Online (Sandbox Code Playgroud)
编译此代码没有错误,也没有警告.运行程序输出1
(不出意外).
现在,让我们深入到陌生的领域.
改变X(bool arg)
以X(int arg)
和,突然间,我们从锵得到一个错误
error: type 'double' cannot be narrowed to 'int' in initializer list [-Wc++11-narrowing]
Run Code Online (Sandbox Code Playgroud)
海湾合作委员会发出警告
warning: …
Run Code Online (Sandbox Code Playgroud) c++ standards-compliance narrowing c++11 list-initialization
std::array<std::pair<int, int>, 2> ids = { { 0, 1 }, { 1, 2 } };
Run Code Online (Sandbox Code Playgroud)
VS2013错误:
错误C2440:'初始化':无法从'int'转换为'std :: pair'没有构造函数可以采用源类型,或构造函数重载解析是不明确的
我究竟做错了什么?
我有这个代码
struct A { A(); A(A&); };
struct B { B(const A&); };
void f(A);
void f(B);
int main() {
f(A());
}
Run Code Online (Sandbox Code Playgroud)
令我惊讶的是,GCC和Clang失败了.例如,Clang说
Compilation finished with errors:
source.cpp:8:10: error: no matching constructor for initialization of 'A'
f(A());
^~~
source.cpp:1:21: note: candidate constructor not viable: expects an l-value for 1st argument
struct A { A(); A(A&); };
^
source.cpp:1:16: note: candidate constructor not viable: requires 0 arguments, but 1 was provided
struct A { A(); A(A&); };
^
source.cpp:4:13: note: passing …
Run Code Online (Sandbox Code Playgroud) 我试图转向C++ 17时遇到了一个奇怪的问题.问题是在C++ 17中有些东西(我不确定是什么)在默认构造函数的情况下使列表初始化的工作方式不同.我试图搜索https://en.cppreference.com/w/cpp/language/list_initialization以获取更多信息,但我没有找到任何看起来相关的信息.
是否有人知道下面的代码在C++ 14中编译但在C++ 17中编译B{}
而不是B()
?(我在gcc 8.2和7.3以及icc 19中尝试过它)
struct A{
protected:
A() {}
};
struct B : public A {};
B f(){
return B(); //compilation OK
//return B{}; //compilation error
}
Run Code Online (Sandbox Code Playgroud) 这特别是关于C++ 11:
#include <iostream>
struct A {
A(){}
int i;
};
struct B : public A {
int j;
};
int main() {
B b = {};
std::cout << b.i << b.j << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
用g ++ 8.2.1编译:
$ g++ -std=c++11 -pedantic-errors -Wuninitialized -O2 a.cpp
a.cpp: In function ‘int main()’:
a.cpp:25:25: warning: ‘b.B::<anonymous>.A::i’ is used uninitialized in this function [-Wuninitialized]
std::cout << b.i << " " << b.j << std::endl
Run Code Online (Sandbox Code Playgroud)
gcc检测b.i
为未初始化,但我认为它应该与零一起进行零初始化b.j
.
我相信正在发生的事情(特别是C++ 11,来自ISO/IEC工作草案N3337,强调我的):
B …
c++ initialization language-lawyer c++11 list-initialization
我偶然发现以下编译:
#include <string>
#include <iostream>
class A{
int i{};
std::string s{};
public:
A(int _i, const std::string& _s) : i(_i), s(_s) {
puts("Called A(int, const std::string)");
}
};
A foo(int k, const char* cstr){
return {k, cstr}; // (*)
}
int main(){
auto a = foo(10, "Hi!");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
感兴趣的线是 (*)。我猜这个函数foo
相当于:
A foo(int k, const char* str){
return A(k, cstr);
}
Run Code Online (Sandbox Code Playgroud)
但是,(*) 中是否有针对此机制的特殊名称?或者仅仅是编译器知道由于返回类型而调用哪个构造函数的简单事实?