用于将默认参数值设置为默认构造函数的更好的语法

有人可能想用一个参数声明一个函数,并指定该参数的默认值是该types的默认构造函数的结果:

void foo(a::really::long::type::name arg = a::really::long::type::name()); 

有没有更好的语法,这不涉及inputtypes名称两次? 就像是:

 void foo(a::really::long::type::name arg = default); 

我意识到我可以键入typedef的types名称,使其更漂亮,但我很好奇这样的语法是否存在。

是:

 void foo(a::really::long::type::name arg = {}); 

总结以下标准定义:

这是列表初始化。 根据types的不同,聚合初始化被执行或对象被初始化,这又意味着默认初始化或零初始化。

当types是std::initializer_list一个特例时,或者types有一个std::initializer_list构造函数(如果它没有默认构造函数时被调用),一些“angular落”


相关的标准报价(为了我们遇到的定义):

§8.3.6默认参数[dcl.fct.default]

1如果在参数声明中指定了初始化子句,则此初始化子句用作默认参数

5使用复制初始化语义(8.5),默认参数与参数typesvariables声明中的初始化程序具有相同的语义约束,

§8.5.4列表初始化[dcl.init.list]

1列表初始化是从一个braced-init-list中初始化一个对象或引用。 这样的初始化器被称为初始化器列表,[…]。 初始化程序列表可能为空。 列表初始化可以在直接初始化或复制初始化上下文中发生; 复制初始化上下文中的列表初始化称为复制列表初始化。

3 Ttypes对象或引用的列表初始化定义如下:

  • 如果T是一个聚合, 则执行聚合初始化 (8.5.1)
  • 否则,如果初始化程序列表中没有元素,并且T是具有默认构造函数的类types,则对该对象进行值初始化
  • 否则,如果T是std :: initializer_list的一个特例,那么将按如下所述构造一个prvalue的initializer_list对象,并根据来自相同types的类(8.5)的一个对象的初始化规则来初始化该对象。
  • 否则,如果T是类types,则考虑构造函数。 枚举适用的构造函数,并通过重载决议(13.3,13.3.1.7)
  • 否则,如果初始化器列表中没有元素,则对该对象进行值初始化

§8.5初始化程序[dcl.init]

8为了初始化 Ttypes的对象,意味着:

  • 如果T是没有默认构造函数(12.1)或用户提供或删除的默认构造函数(可能是cv-qualified)的类types(第9章),则该对象被默认初始化 ;
  • 如果T是没有用户提供或删除的默认构造函数的(可能是cv-qualified)类types,那么该对象是零初始化的,并且检查用于缺省初始化的语义约束,并且如果T具有非平凡的默认构造函数,对象被默认初始化 ;
  • 如果T是一个数组types,那么每个元素都是值初始化的 ;
  • 否则,该对象是零初始化的

7 默认初始化typesT的对象意味着:

  • 如果T是(可能是cv-qualified)类types(第9章), 则调用T的默认构造函数(12.1) (并且如果T没有默认构造函数或重载parsing(13.3)模糊性或从初始化上下文中删除或不可访问的函数中);
  • 如果T是数组types,则每个元素都是默认初始化的 ;
  • 否则,不执行初始化。

6 初始化 Ttypes的对象或引用意味着:

  • 如果T是标量types(3.9),则将对象初始化为通过将整数字面量0(零)转换为T获得的值;
  • 如果T是一个(可能是cv合格的)非联合类types,那么每个非静态数据成员和每个基类子对象都是零初始化的,并且填充被初始化为0位;
  • 如果T是(可能是cv限定的)联合types,则该对象的第一个非静态命名数据成员是零初始化的,并且填充初始化为零位;
  • 如果T是一个数组types,则每个元素都是零初始化的;
  • 如果T是引用types,则不执行初始化。

§13.3.1.7通过列表初始化初始化[over.match.list]

1当非聚合类typesT的对象被列表初始化(8.5.4)时,重载parsing分两个阶段select构造函数:

  • 最初,候选函数是类T的初始化程序列表构造函数 (8.5.4),而参数列表由作为单个参数的初始化程序列表组成。
  • 如果找不到可行的初始化列表构造函数,则重新执行重载parsing,其中候选函数是类T的所有构造函数,参数列表由初始化程序列表的元素组成。

如果初始化器列表中没有元素,并且T有一个默认的构造器,则第一个阶段被省略。 […]

如果你控制了arg的类,那么行人的方法是可能的。 为enum使用重载的转换构造函数:

 // Define this enum, and then write constructors which take dfl enum dfl { dflval }; class a_really_long_type_name { public: a_really_long_type_name(dfl arg = dflval); }; 

现在foo可以是:

 void foo(a_really_long_type_name arg = dflval); 

如果你能应用这个,好处是可移植性; 这应该在一个二十五岁的C ++编译器中正常工作。

多个类都可以共享这个dfl enum和它的dflval -flavored零; 这就像有一个新的关键字。

因为enum是一个不同的types,所以不会影响整数types或字符的构造函数重载等等。

不利的一面是,它已经通过默认参数提供了一些默认的类,这会导致重复的构造函数代码。