Scott Meyers 撰写的Effective C++ 11草案规定:
在创建对象时区分()和{}
Object obj(args...)和之间有什么区别Object obj{args...}?为什么斯科特这么说.
更新:
问题如何使用C++ 11统一初始化语法?请问如何,这个问题问为什么.
UPDATE2:
我发现以下链接很有帮助,完全回答了这个问题:
此代码示例是否有效?
using ref = char&;
ref foo(ref x) {
return ref{x};
}
int main() {
char a;
foo(a);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
似乎:
gcc 4.9说没有
main.cpp: In function 'char& foo(ref)':
main.cpp:4:15: error: invalid cast of an rvalue expression of type 'char' to type 'ref {aka char&}'
return ref{x};
^
Run Code Online (Sandbox Code Playgroud)http://coliru.stacked-crooked.com/a/cb6604b81083393f
那么哪个编译器是对的?还是未指明?
这很容易克服gcc构建错误:
使用括号而不是括号
ref foo(ref x) {
return ref(x);
}
Run Code Online (Sandbox Code Playgroud)通过命名返回值
ref foo(ref x) {
ref ret{x};
return ret;
}
Run Code Online (Sandbox Code Playgroud)选项1.打破统一初始化,选项2.添加无用的代码行.
类似的问题在这里已经解决了: 为什么我不能在初始化列表中使用统一初始化初始化引用?
但是提到的pr50025在gcc 4.9中是固定的.
我知道上面的代码示例是没用的,但我故意过度简化它以指出问题.在现实生活中,代码问题可以隐藏在通用函数中,例如:
#include <utility>
template …Run Code Online (Sandbox Code Playgroud) 我在用一些琐碎的代码排列时就注意到了这一点:
struct Base0 {};
struct Base1 {};
template<typename... Ts>
struct Derived: Ts... {};
int main() {
Derived<Base0, Base1> d0 {Base0{}, Base1{}}; // OK
Derived<Base0, Base1> d1 (Base0{}, Base1{}); // ERROR
}
Run Code Online (Sandbox Code Playgroud)
我认为两者d0并d1应导致编译错误,因为我看不出Derived没有任何匹配的构造函数需要构造函数参数如通过和标志d0的编译细。
我可能想念一些明显的东西。使它通过的统一初始化是什么?是聚合初始化还是什么?临时人员传给ctor的情况如何?
编辑
根据要求,我提供了喷出的副本粘贴:
main.cpp: In function ‘int main()’:
main.cpp:9:47: error: no matching function for call to ‘Derived::Derived(Base0, Base1)’
Derived<Base0, Base1> d1 (Base0{}, Base1{}); // ERROR
^
main.cpp:5:8: note: candidate: constexpr Derived::Derived()
struct Derived: Ts... {};
^~~~~~~
main.cpp:5:8: …Run Code Online (Sandbox Code Playgroud) 使用g ++ 4.7.0(-Wall -Wextra -Werror -Wconversion -std=c++11)编译此代码:
#include <iostream> // std::cout, std::endl
#include <string> // std::string
#include <utility> // std::move
void out(std::string const &message)
{
static int count{0};
std::cout << count++ << " = " << message << std::endl;
}
struct Foo
{
Foo() {out("constructor");}
~Foo() {out("destructor");}
Foo(Foo const &) {out("copy constructor");}
Foo & operator=(Foo const &) {out("copy via assignment"); return *this;}
Foo(Foo &&) {out("move constructor");}
Foo & operator=(Foo &&) {out("move via assignment"); return *this;}
};
int main() …Run Code Online (Sandbox Code Playgroud) 考虑以下程序:
struct X
{
X(int, int) { }
X(X&&) { }
};
int main()
{
X x( {0, 1} ); // Doesn't compile on ICC 13.0.1, compiles on
// Clang 3.2, GCC 4.7.2, and GCC 4.8.0 beta.
}
Run Code Online (Sandbox Code Playgroud)
使用GCC 4.7.2,GCC 4.8.0和Clang 3.2编译时,该程序执行以下操作(*):
X传递值0和1构造函数,然后;X从那个临时移动构造.相反,使用ICC 13.0.1,它不会编译.
问题#1:谁是对的?
(*)实际上,临时的创建和对移动构造函数的调用都被省略了,但是使用该-fno-elide-constructors选项进行编译并向构造函数添加一些打印输出可以发现这是正在发生的事情.
现在考虑以下,上述程序的轻微变化,其中统一初始化用于直接初始化x:
int main()
{
X x{ {0, 1} }; // ERROR! Doesn't compile.
// ^........^
}
Run Code Online (Sandbox Code Playgroud)
我不希望在这里使用大括号而不是括号来改变任何东西,但不知何故:这个程序不能在我测试过的任何 …
以下代码使用XCode 5.0但不是Visual Studio 2013编译正常.
#include <vector>
class VectorInit
{
private:
std::vector<int> m_vector{1, 2, 3}; // fails to compile using VS 2013
};
int main()
{
std::vector<int> vector{1, 2, 3};
VectorInit vectorInit;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这是Visual Studio报告的错误:
Error 1 error C2664: 'std::vector<int,std::allocator<_Ty>>::vector(std::initializer_list<int>,const std::allocator<_Ty> &)' : cannot convert argument 3 from 'int' to 'const std::allocator<_Ty> &' c:\visual studio 2013\projects\vector-init\main.cpp 6 1 vector-init
Run Code Online (Sandbox Code Playgroud)
我还没有设法找到一个如何在类定义中初始化这样的向量的示例.
哪个编译器正确?
如果语法无效,是在构造函数初始化列表中初始化m_vector的唯一选项吗?
几天前我发现了统一初始化,我看到每个人都应该尽可能地使用它.
但是,我不禁想到这种新语法比它的价值更麻烦......
第一个例子
假设我写了一个库,其中我有一个像这样的结构:
struct MyStruct
{
int member0;
int member1;
}
Run Code Online (Sandbox Code Playgroud)
用户可以使用聚合初始化来编写类似的东西:
MyStruct myVar = {0, 1}; // member0 = 0 and member1 = 1
Run Code Online (Sandbox Code Playgroud)
现在,让我们说我更新了我的库,结构现在看起来像这样:
struct MyStruct
{
int member0;
int member1;
MyStruct(int p0, int p1) : member0(p1), member1(p0){}
}
Run Code Online (Sandbox Code Playgroud)
在C++ 11之前,用户代码将停止编译,这会强制用户重写他的代码并使用构造函数.但是现在,代码将被编译并被解释为统一初始化:
MyStruct myVar = {0, 1}; // member0 = 1 and member1 = 0
Run Code Online (Sandbox Code Playgroud)
没有用户知道,更新他的库将使他的代码做一些非常不同的事情!
第二个例子
现在,让我们说我的库里有这样一个类:
class MyClass
{
public:
MyClass(int size, int default = 0) : elements(size, default){}
private:
std::vector<int> elements;
}
Run Code Online (Sandbox Code Playgroud)
用户可以像这样使用它:
MyClass myVar …Run Code Online (Sandbox Code Playgroud) 正如C++标准(工作草案)所说:
9.5.1 [class.union]
在并集中,至多一个非静态数据成员可以在任何时间处于活动状态,也就是说,任何时候最多一个非静态数据成员的值都可以存储在并集中.[...] union的大小足以包含其中最大的非静态数据成员.每个非静态数据成员都被分配,就好像它是结构的唯一成员一样.union对象的所有非静态数据成员都具有相同的地址.
但我不知道如何识别哪个是工会的活跃成员,而且我没有用到足够深入标准来找到标准所说的内容,我试图弄清楚活动成员是如何设置的但我发现它是如何交换的:
9.5.4 [class.union]
[ 注意:通常,必须使用显式析构函数调用和放置新运算符来更改联合的活动成员.- 注完 ] [ 实施例:考虑的对象
u的union type U类型的具有非静态数据成员米M和n类型的N.如果M有一个非平凡的析构函数并且N有一个非平凡的构造函数(例如,如果它们声明或继承虚函数),则可以安全地将u的活动成员切换m为n使用析构函数和placement new运算符,如下所示:Run Code Online (Sandbox Code Playgroud)u.m.~M(); new (&u.n) N;- 结束例子 ]
所以我的猜测是,工会的活跃成员是首先签署,使用,构建或放置新的成员; 但是这对于统一初始化变得有点棘手,请考虑以下代码:
union Foo
{
struct {char a,b,c,d;};
char array[4];
int integer;
};
Foo f; // default ctor
std::cout << f.a << f.b << f.c << f.d << '\n';
Run Code Online (Sandbox Code Playgroud)
哪个是上面代码的联合的活跃成员?是 …
在将我的一些C++ 98代码更新到C++ 11时,我发现统一初始化并不是那么统一.其中一些与不完整类型相关void,而其他与pod有关.例如,对于简单的可复制类型,当初始化涉及复制/移动构造函数时,统一初始化对于直接初始化或复制初始化都不起作用.
例如
template<class T>
T foo() { return T("Hello World");}
foo<void>();
foo<std::string>();
--------
template<class T>
T foo() { return T{"Hello World"};}
foo<void>();
foo<std::string>();
Run Code Online (Sandbox Code Playgroud)
虽然第一部分编译,但后半部分失败了 error: compound literal of non-object type 'void'
struct pod { int x;int y;};
pod p{1,2}; //ok pod p(1,2) is error as usual
pod p2(p);
struct foo
{
foo(foo const& rhs) : p_(rhs.p_){}
pod p_;
};
--------
struct pod { int x;int y;};
pod p{1,2};
pod p2{p};
struct foo
{
foo(foo const& rhs) …Run Code Online (Sandbox Code Playgroud) 我正在尝试将long类型变量转换为int带有uniform initialization和不带有它的类型变量。但是我只有在统一初始化时才会收到编译器警告。这是为什么?为什么gcc在这两种情况下都不发出警告?我也尝试过clang并得到了类似的结果。
这是代码
#include <iostream>
int main() {
long l = 1;
int i1 = l;
int i2 = { l };
std::cout << i1 << std::endl;
std::cout << i2 << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我得到的唯一警告
$ g++ -Wall -Wextra 1.cpp
1.cpp: In function ‘int main()’:
1.cpp:6:16: warning: narrowing conversion of ‘l’ from ‘long int’ to ‘int’ inside { } [-Wnarrowing]
int i2 = { l };
Run Code Online (Sandbox Code Playgroud) c++ compiler-warnings language-lawyer uniform-initialization c++11