C++11统一初始化:初始化列表和多参数构造函数之间的歧义?

7

目前正在努力理解C++11统一初始化。我遇到了这种模棱两可的情况:考虑一个类,它可以通过两个参数构造函数或任意长度的初始化列表进行构造:

class Foo {
  public:
    Foo(int a, int b) {
      std::cout << "constructor 1" << std::endl;
    }
    Foo(std::initializer_list<int>) {
      std::cout << "constructor 2" << std::endl;
    }
};

遵循统一初始化惯例,我期望以下内容可以工作:

Foo a (1, 2) 输出 constructor 1(显然)

Foo b {1, 2} 输出 constructor 1

Foo c = {1, 2} 输出 constructor 2

但是,似乎编译器将Foo b {1, 2}解释为列表初始化,并调用构造函数2。当存在初始化列表构造函数时,()语法是强制编译器考虑其他类型的构造函数唯一的方式吗?


3
相关:https://dev59.com/EGkw5IYBdhLWcg3wUI_x -- 尽管我在SO上找不到太多有关std :: vector的提及,但它是一个“典型例子”。 - user202729
3个回答

1
您可以在构造函数中添加一个额外的忽略参数,以指定特定的重载调用站点,就像STL中所做的那样:
#include <iostream>

struct non_init_list_t {};
inline constexpr non_init_list_t non_init_list;

struct Class {
    Class(int a, int b, non_init_list_t = non_init_list) { std::clog << "()\n"; }
    Class(std::initializer_list<int> list) { std::clog << "{}\n"; }
};

Class a{12, 42, non_init_list};  // ()
Class b{12, 42};                 // {}
Class c(12, 42);                 // ()

1
似乎编译器将 Foo b {1, 2} 解释为列表初始化,并调用构造函数 2。当存在初始化器列表构造函数时,() 语法是强制编译器考虑其他类型构造函数的唯一方法吗?
标准草案引用了以下内容:9.4.5.2 [dcl.init.list](我强调):
如果构造函数的第一个参数类型为 std::initializer_list 或 cv std::initializer_list 的某个类型 E 的引用,并且没有其他参数,或者所有其他参数都有默认参数,则此构造函数是初始化器列表构造函数。
注 2:在列表初始化中,初始化器列表构造函数优先于其他构造函数。将初始化器列表作为类 C 的构造函数模板模板 C(T) 的参数传递不会创建初始化器列表构造函数,因为初始化器列表参数导致相应的参数成为非推断上下文。

并且 12.4.2.8 [over.match.list]

当非聚合类类型 T 的对象通过列表初始化的方式进行初始化,使得[dcl.init.list]指定根据本子句中的规则执行重载决议,或者根据[over.ics.list]形成列表初始化序列时,重载决议分两个阶段选择构造函数:

  • 如果初始化器列表不为空或T没有默认构造函数,则首先执行重载决议,其中候选函数是类T的初始化器列表构造函数[dcl.init.list],参数列表由初始化器列表作为单个参数组成。

  • 否则,或者如果找不到可行的初始化器列表构造函数,则再次执行重载决议,其中候选函数是类T的所有构造函数,并且参数列表由初始化器列表的元素组成。


0
如果构造函数有initializer_list版本,编译器将首先将其解释为initializer_list,如果没有initializer_list版本,则编译器将将其解释为另一个重载版本。如果编译器将其解释为另一个版本,并且您想调用使用initializer_list版本的构造函数,恰好参数的数量和类型与其他构造函数相同,那么您将会导致错误。然后编译器选择initializer_list版本还是其他版本?因此,使用括号表示法绝对不是initializer_list版本。如果您的构造函数中没有initializer_list版本,请不要担心这个问题。
顺便说一下,如果您使用auto自动推断类型,请勿使用统一初始化。它必须将类型解释为initializer_list

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接