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

Calling constructor with braces instead parantheses

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

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

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

#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;
}

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

#include <initializer_list>

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

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

所以,总而言之,我的问题如下:委托构造函数时是否有特殊规则,允许仅使用大括号调用初始化列表构造函数,例如 Foo{something}

是的,mem-initializer 例如 Foo{42} 可以包含带括号的 expression-listbraced-init-list。无论 mem-initializer-id 是否表示构造函数的 class、基础 class 或成员,情况都是如此:也就是说,当构造函数委托和何时不委托。请参阅 [class.base.init].

中的语法

此外,标准规定(C++14 中的[class.base.init]/7)由表达式列表 初始化braced-init-list 根据通常的初始化规则出现。因此,如果初始化程序是 braced-init-list,那么 std::initializer_list 构造函数将在重载决议中受到青睐。

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

If the name of the class itself appears as class-or-identifier in the member initializer list, then the list must consist of that one member initializer only; such constructor is known as the delegating constructor, and the constructor selected by the only member of the initializer list is the target constructor In this case, the target constructor is selected by overload resolution and executed first, then the control returns to the delegating constructor and its body is executed.

因此,通过重载决策,您可以像在 'normal' 代码中调用它一样调用初始化列表构造函数,因为。

但是,我不知道有什么可以允许调用接受初始化列表的函数,就像您可以使用初始化列表调用构造函数一样。

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

The body of a function definition of any constructor, before the opening brace of the compound statement, may include the member initializer list, whose syntax is the colon character :, followed by the comma-separated list of one or more member-initializers, each of which has the following syntax
     class-or-identifier (expression-list(optional) ) (1)
     class-or-identifier brace-init-list (2) (since C++11)
      parameter-pack ... (3) (since C++11)

1) Initializes the base or member named by class-or-identifier using direct initialization or, if expression-list is empty, value-initialization
2) Initializes the base or member named by class-or-identifier using list-initialization (which becomes value-initialization if the list is empty and aggregate-initialization when initializing an aggregate)
3) Initializes multiple bases using a pack expansion

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