使用大括号调用构造函数而不是括号

时间:2015-04-21 23:51:59

标签: c++ c++11 constructor initializer-list delegating-constructor

我最近意识到在C ++ 11中我们可以调用委托初始化列表构造函数,如

Foo() : Foo{42} // delegate to Foo(initializer_list<>)

这种语法是否正确?它似乎是,虽然我希望在调用函数时总是使用括号,例如Foo({42})。 clang ++和g ++中的compiles fine下面的示例代码

#include <iostream>
#include <initializer_list>

struct Foo
{
    Foo() : Foo{42} // I would have expected invalid syntax, use Foo({42})
    {
        std::cout << "Foo()... delegating constructor\n";
    }
    Foo(std::initializer_list<int>)
    {
        std::cout << "Foo(initializer_list)\n";
    }
};

int main()
{
    Foo foo;
}

我很清楚统一初始化,比如使用{ }声明对象,但不知道我们也可以调用构造函数。我们无法调用函数,但以下doesn't compile

#include <initializer_list>

void f(std::initializer_list<int>){}

int main()
{
    f{5}; // compile time error, must use f({5})
}

总而言之,我的问题如下:委托构造函数时是否有特殊规则,允许仅使用大括号调用init-list构造函数,如Foo{something}

2 个答案:

答案 0 :(得分:5)

是的, mem-initializer ,例如Foo{42},可以包含带括号的表达式列表 braced-init-list 。无论 mem-initializer-id 是否表示构造函数的类,基类或成员,都是这种情况:即,在构造函数委托时和何时不表示。请参阅[class.base.init]中的语法。

此外,标准指定(C ++ 14中的[class.base.init] / 7) expression-list braced-init-list 根据通常的初始化规则发生。因此,如果初始化程序是 braced-init-list ,那么std::initializer_list构造函数将在重载解析中受到青睐。

答案 1 :(得分:2)

我认为规则非常明确,您将被允许委托给初始化列表构造函数(强调我的):

  

如果类的名称本身在类中显示为class-or-identifier   成员初始化列表,然后列表必须包含该成员   仅初始化程序;这样的构造函数称为委托   构造函数,以及由唯一成员选择的构造函数   初始化列表是目标构造函数在这种情况下,目标   构造函数由重载决策选择并首先执行,   然后控件返回委托构造函数,其主体是   执行。

因此,通过重载解析,您可以调用初始化列表构造函数,就像在“普通”代码中调用它一样,因为。

但是,我不知道应该允许调用接受初始化列表的函数的方法与调用构造函数的方法相同。

编辑:More关于构造函数规则(再次强调我的):

  

任何构造函数的函数定义的主体,在之前   复合语句的开括号,可以包含成员   初始化列表,其语法为冒号字符:,后跟   逗号分隔的一个或多个成员初始值设定项列表   它具有以下语法
   class-or-identifier(表达式列表(可选))(1)
   class-or-identifier brace-init-list(2)(自C ++ 11起)
  parameter-pack ...(3)(自C ++ 11起)

     

1)使用class初始化由class-or-identifier命名的基类或成员   直接初始化,或者,如果表达式列表为空,   价值初始化
  2)初始化名为的基数或成员   使用列表初始化的类或标识符(变为   如果列表为空并且聚合初始化,则初始化值   初始化聚合时)
  3)使用a初始化多个碱基   包装扩张

所以根据#2,它似乎是合法的。