标签: list-initialization

为什么列表初始化(使用花括号)比替代品更好?

MyClass a1 {a};     // clearer and less error-prone than the other three
MyClass a2 = {a};
MyClass a3 = a;
MyClass a4(a);
Run Code Online (Sandbox Code Playgroud)

为什么?

我在SO上找不到答案,所以让我回答一下我自己的问题.

c++ syntax initialization c++11 list-initialization

349
推荐指数
5
解决办法
13万
查看次数

111
推荐指数
3
解决办法
2万
查看次数

删除了默认构造函数.仍然可以创建对象......有时候

c ++ 11统一初始化语法的天真,乐观和哦......错误的观点

我认为,因为C++ 11用户定义的类型对象应该使用新{...}语法而不是旧(...)语法构造(除了构造函数重载std::initializer_list和类似参数(例如std::vector:size ctor vs 1 elem init_list ctor)).

好处是:没有狭义的隐式转换,最烦人的解析没有问题,一致性(?).我没有看到任何问题,因为我认为它们是相同的(除了给出的例子).

但他们不是.

一个纯粹疯狂的故事

{}调用默认的构造函数.

......除非:

  • 删除默认构造函数
  • 没有定义其他构造函数.

然后它看起来像是值而不是初始化对象?...即使对象已经删除了默认构造函数,{}也可以创建一个对象.这不是打败了删除的构造函数的全部目的吗?

......除非:

  • 该对象有一个删除的默认构造函数和
  • 其他构造函数定义.

然后失败了call to deleted constructor.

......除非:

  • 该对象有一个删除的构造函数和
  • 没有其他构造函数定义和
  • 至少是一个非静态数据成员.

然后失败并丢失了字段初始值设定项.

但是,您可以使用它{value}来构造对象.

好吧也许这与第一个异常相同(值init对象)

......除非:

  • 该类有一个删除的构造函数
  • 并且至少有一个数据成员默认初始化.

然后也{}不能{value}创建一个对象.

我相信我错过了一些.具有讽刺意味的是,它被称为统一初始化语法.我再说一遍:UNIFORM初始化语法.

这种疯狂是什么?

情景A.

删除默认构造函数:

struct foo {
  foo() = delete;
};

// All bellow OK (no errors, no warnings) …
Run Code Online (Sandbox Code Playgroud)

c++ language-lawyer aggregate-initialization list-initialization c++14

49
推荐指数
3
解决办法
6977
查看次数

为什么Clang和VS2013接受移动大括号初始化的默认参数,但不接受GCC 4.8或4.9?

就像标题所暗示的那样,我有一个简短的演示程序可以编译所有这些编译器,但是在使用gcc 4.8和gcc 4.9进行编译后运行的核心转储:

任何想法为什么?

#include <unordered_map>

struct Foo : std::unordered_map<int,int> {
    using std::unordered_map<int, int>::unordered_map;
    // ~Foo() = default; // adding this allows it to work
};

struct Bar {
    Bar(Foo f = {}) : _f(std::move(f)) {}
    // using any of the following constructors fixes the problem:
    // Bar(Foo f = Foo()) : _f(std::move(f)) {}
    // Bar(Foo f = {}) : _f(f) {}

    Foo _f;
};

int main() {
    Bar b;

    // the following code works as expected
    // Foo f1 …
Run Code Online (Sandbox Code Playgroud)

c++ gcc c++11 list-initialization

48
推荐指数
1
解决办法
1650
查看次数

集成初始化的C++ 17扩展是否使得大括号初始化变得危险?

似乎普遍认为,大括号初始化应优先于其他形式的初始化,但是由于将C++ 17 扩展引入聚合初始化,似乎存在意外转换的风险.请考虑以下代码:

struct B { int i; };
struct D : B { char j; };
struct E : B { float k; };

void f( const D& d )
{
  E e1 = d;   // error C2440: 'initializing': cannot convert from 'D' to 'E'
  E e2( d );  // error C2440: 'initializing': cannot convert from 'D' to 'E'
  E e3{ d };  // OK in C++17 ???
}

struct F
{
  F( D d ) …
Run Code Online (Sandbox Code Playgroud)

c++ initialization list-initialization c++17

48
推荐指数
2
解决办法
3893
查看次数

std :: array初始化中的brace elision

假设有一个std::array要初始化的东西.如果使用双括号可以:

std::array<int, 2> x = {{0, 1}};
std::array<int, 2> x{{0, 1}};
Run Code Online (Sandbox Code Playgroud)

在良好的旧聚合初始化中使用单个括号也是可以的,因为括号省略将处理缺少的大括号:

std::array<int, 2> x = {0, 1};
Run Code Online (Sandbox Code Playgroud)

但是,使用单个括号的列表初始化是否可以?GCC接受它,Clang拒绝它"在使用直接列表初始化时不能省略关于子对象初始化的大括号".

std::array<int, 2> x{0, 1};
Run Code Online (Sandbox Code Playgroud)

提到括号内容的标准中唯一的部分是8.5.1/12,其中说:

使用赋值表达式初始化聚合成员时,将考虑所有隐式类型转换(第4节).如果赋值表达式可以初始化成员,则初始化成员.否则,如果成员本身是子集合,则假定使用大括号,并考虑赋值表达式初始化子集合的第一个成员.

8.5.1是关于聚合初始化的,所以应该意味着Clang是正确拒绝的,对吗?没那么快.8.5.4/3说:

列表初始化对象或类型T的引用定义如下:

[...]

- 否则,如果T是聚合,则执行聚合初始化(8.5.1).

我认为这意味着与聚合初始化完全相同的规则,包括括号elision,适用,意味着GCC是正确的接受.

我承认,措辞不是特别清楚.那么,哪个编译器正确处理第三个片段呢?括号省略是否在列表初始化中发生,或者不是?

c++ language-lawyer aggregate-initialization c++11 list-initialization

46
推荐指数
2
解决办法
5635
查看次数

为什么这段代码在没有类型不匹配错误的情况下编译(C++ 11)?

std::vector<char> p = {"abc", "def"};
Run Code Online (Sandbox Code Playgroud)

"abc"并且"def"不是char,为什么编译器没有给我一个关于这种类型不匹配的错误?

c++ c++11 list-initialization

45
推荐指数
1
解决办法
1656
查看次数

为什么标准区分直接列表初始化和复制列表初始化?

我们知道这T v(x);被称为直接初始化,而T v = x;被称为复制初始化,这意味着它将构造一个临时Tx,将被复制/移入v(很可能被省略).

对于列表初始化,标准根据上下文区分两种形式.T v{x};称为直接列表初始化,T v = {x};称为复制列表初始化:

§8.5.4 [dcl.init.list] p1

[...]列表初始化可以在直接初始化或复制初始化上下文中进行; 直接初始化上下文中的列表初始化称为直接列表初始化,复制初始化上下文中的列表初始化称为复制列表初始化.[...]

但是,整个标准中只有两个引用.对于直接列表初始化,在创建像T{x}(§5.2.3/3)这样的临时表时会提到它.对于copy-list-initialization,它用于返回语句中的表达式,如return {x};(§6.6.3/2).

现在,下面的片段怎么样?

#include <initializer_list>

struct X{
  X(X const&) = delete; // no copy
  X(X&&) = delete; // no move
  X(std::initializer_list<int>){} // only list-init from 'int's
}; …
Run Code Online (Sandbox Code Playgroud)

c++ language-lawyer c++11 list-initialization

37
推荐指数
1
解决办法
2782
查看次数

为什么我不能括起来初始化从另一个结构派生的结构?

当我运行此代码时:

struct X {
    int a;
};

struct Y : public X {};

X x = {0};
Y Y = {0};
Run Code Online (Sandbox Code Playgroud)

我明白了:

error: could not convert ‘{0}’ from ‘<brace-enclosed initializer list>’ to ‘Y’
Run Code Online (Sandbox Code Playgroud)

为什么大括号初始化适用于基类而不适用于派生类?

c++ struct c++11 list-initialization

37
推荐指数
2
解决办法
8660
查看次数

支撑数如何影响均匀初始化?

请考虑以下代码段:

#include <iostream>

struct A {
  A() {}
  A(const A&) {}
};

struct B {
  B(const A&) {}
};

void f(const A&) { std::cout << "A" << std::endl; }
void f(const B&) { std::cout << "B" << std::endl; }

int main() {
  A a;
  f(   {a}   ); // A
  f(  {{a}}  ); // ambiguous
  f( {{{a}}} ); // B
  f({{{{a}}}}); // no matching function
}
Run Code Online (Sandbox Code Playgroud)

为什么每个调用都会编写相应的输出?支撑数如何影响均匀初始化?支撑精益如何影响这一切?

c++ language-lawyer uniform-initialization c++11 list-initialization

31
推荐指数
1
解决办法
710
查看次数