2

由于 C++11 引入了新的统一初始化语法,许多人建议使用它来代替旧式语法。至少,如果不是因为这种所谓的极端情况:

struct Foo {
    Foo(int){
        std::cout << "default" << std::endl;
    }
    Foo(std::initializer_list<int>){
        std::cout << "initlist" << std::endl;
    }
};
int main(){
    Foo f{200}; //prints "initlist" 
}

使用 {}-always-style 会带来麻烦,尤其是在模板中。新语法似乎只有三种安全用法:

  1. 显式请求 std::initializer_list-constructors
  2. POD 构造函数
  3. 默认构造函数

但也有一种情况,我们必须使用统一的初始化语法:非静态数据成员初始化器。由于某种原因,C++ 可以识别

void Bar() {
    Foo f(200);
}

但无法处理

struct Bar {
    Foo f(200);
};

问题 #1:为什么 () 语法在函数内部起作用而不是在类中起作用?有谁知道这背后的原理?

综上所述,最后我们遇到了这个愚蠢的案例:

struct FooBar {
    std::vector<int> bar(50); //doesn't work
    std::vector<int> bar{50}; //not the intended effect
    std::vector<int> bar = std::vector<int>(50); //works
};

当然,您也不能将 auto 用于数据成员。所以我要么不得不笨拙地混合所有语法,要么根本不使用这些功能。

问题2:我是不是误会了什么?这不可能是预期的行为,可以吗?

4

2 回答 2

1

问题 #1:为什么 () 语法在函数内部起作用而不是在类中起作用?有谁知道这背后的原理?

因为它看起来像一个函数声明,并且已经有足够的混淆:

Foo f(); // function declaration. This still catches people out

但是您可以使用(),只需使用复制初始化语法:

T t = T(args);

问题2:我是不是误会了什么?这不可能是预期的行为,可以吗?

这是设计行为。不幸的是,它不能很好地与某些类型的标准库容器(如std::vector<int>您的示例中)一起使用。您只需要记住隐式initializer_list构造函数胜过所有其他兼容的构造函数。你应该努力设计你自己的类,这样它们就不会遇到这个问题。

请参阅此相关问题:何时使用大括号括起来的初始化程序?

于 2014-04-18T09:24:21.767 回答
0

这是不允许的,因为它会导致更多的“最烦人的解析”实例,这已经很烦人了。这不是主要障碍,因为您仍然可以在构造函数主体中使用初始化语法,或者使用复制初始化形式。

如果您牢记大括号括起来的列表的语义是并且一直是提供要存储在对象中的值列表,那么很明显std::vector<int> bar{50}应该(并且确实)创建一个包含一个 int 的向量。

于 2014-04-18T09:49:04.200 回答