应对C ++ 11初始化语法

时间:2014-02-17 11:36:36

标签: c++ c++11 uniform-initialization

由于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风格的尖叫来解决问题,特别是在模板中。新语法似乎只有三个安全用法:

  1. 显式请求std :: initializer_list-constructors
  2. POD-构造
  3. 默认构造
  4. 但是还有一种情况我们必须使用统一的初始化语法:非静态数据成员初始化器。 出于某种原因,C ++可以识别

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

    但无法处理

    struct Bar {
        Foo f(200);
    };
    

    问题#1:为什么()-syntax在函数内部工作但不在类中?有谁知道这背后的理由?

    总而言之,最后我们得出了这个愚蠢的案例:

    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:我误解了什么吗?这不是预期的行为,可以吗?

2 个答案:

答案 0 :(得分:1)

  

问题#1:为什么()-syntax在函数内部工作但不在类中?有谁知道这背后的理由?

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

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

可以使用(),只需使用 copy-initialization 语法:

T t = T(args);
  问题2:我误解了什么吗?这不是预期的行为,可以吗?

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

请参阅此相关问题:When to use a brace-enclosed initializer?

答案 1 :(得分:0)

这是不被允许的,因为它会导致更多令人烦恼的解析&#34;这已经很烦了。这不是一个主要障碍,因为您仍然可以在构造函数体中使用初始化语法,或使用复制初始化表单。

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