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

时间:2022-08-10 10:51:16

One might want to declare a function with an argument, and specify that the default value for the argument is the result of the type's default constructor:

可能需要声明一个带有参数的函数,并指定参数的默认值是类型的默认构造函数的结果:

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

Is there a nicer syntax for this that doesn't involve entering the type name twice? Something like:

有没有更好的语法,不需要输入两次类型名?喜欢的东西:

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

I realize I can typedef the type name to make it prettier, but I'm curious whether such a syntax exists.

我意识到我可以用typedef类型名称来使它更漂亮,但是我很好奇这种语法是否存在。

2 个解决方案

#1


55  

Yes:

是的:

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

To sum up the following standard definitions:

总结以下标准定义:

This is list initialization. Depending of the type, aggregate initialization is performed or the object is value initialized, which in turn implies default initialized or zero initialized.

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

Some "corner" cases are when the type is a specialization of std::initializer_list or when the type has a std::initializer_list constructor (it is called if it has no default constructor)

有些“拐角”情况是当类型是std::initializer_list的专门化时,或者当类型具有std:::initializer_list构造函数时(如果没有默认构造函数,则调用它)


The relevant standard quotes (in order we encounter definitions):

相关的标准引号(按我们遇到定义的顺序):

§8.3.6 Default arguments [dcl.fct.default]

§求值默认参数(dcl.fct.default)

1 If an initializer-clause is specified in a parameter-declaration this initializer-clause is used as a default argument

如果参数声明中指定了initializer-子句,则将该initializer-子句用作默认参数

5 The default argument has the same semantic constraints as the initializer in a declaration of a variable of the parameter type, using the copy-initialization semantics (8.5)

5默认参数具有与参数类型变量声明中的初始化器相同的语义约束,使用复制初始化语义(8.5)

§8.5.4 List-initialization [dcl.init.list]

§8.5.4 List-initialization[dcl.init.list]

1 List-initialization is initialization of an object or reference from a braced-init-list. Such an initializer is called an initializer list, [...]. An initializer list may be empty. List-initialization can occur in direct-initialization or copy initialization contexts; [..] list-initialization in a copy-initialization context is called copy-list-initialization.

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

3 List-initialization of an object or reference of type T is defined as follows:

对于T类型的对象或引用的列表初始化定义如下:

  • If T is an aggregate, aggregate initialization is performed (8.5.1)
  • 如果T是一个聚合,则执行聚合初始化(8.5.1)
  • Otherwise, if the initializer list has no elements and T is a class type with a default constructor, the object is value-initialized.
  • 否则,如果初始化器列表没有元素,而T是带有默认构造函数的类类型,则该对象是值初始化的。
  • Otherwise, if T is a specialization of std::initializer_list, a prvalue initializer_list object is constructed as described below and used to initialize the object according to the rules for initialization of an object from a class of the same type (8.5).
  • 否则,如果T是std的专门化::initializer_list,将构造一个prvalue initializer_list对象,并根据该对象的初始化规则对对象进行初始化(8.5)。
  • Otherwise, if T is a class type, constructors are considered. The applicable constructors are enumerated and the best one is chosen through overload resolution (13.3, 13.3.1.7) [...]
  • 否则,如果T是类类型,则考虑构造函数。列出适用的构造函数,通过重载解析(13.3,13.3.1.7)[…]
  • ...
  • Otherwise, if the initializer list has no elements, the object is value-initialized.
  • 否则,如果初始化器列表没有元素,那么对象就是value-initialized。

§ 8.5 Initializers [dcl.init]

§8.5初始化(dcl.init)

8 To value-initialize an object of type T means:

8对值初始化类型为T的对象意味着:

  • if T is a (possibly cv-qualified) class type (Clause 9) with either no default constructor (12.1) or a default constructor that is user-provided or deleted, then the object is default-initialized;
  • 如果T是一个(可能是cv限定的)类类型(第9条),没有默认构造函数(12.1)或默认构造函数(用户提供或删除),则对象是默认初始化的;
  • if T is a (possibly cv-qualified) class type without a user-provided or deleted default constructor, then the object is zero-initialized and the semantic constraints for default-initialization are checked, and if T has a non-trivial default constructor, the object is default-initialized;
  • 如果T是一个(可能是cv限定的)类类型,没有用户提供的或删除的默认构造函数,则对象为零初始化,检查默认初始化的语义约束,如果T有一个非平凡的默认构造函数,则对象为缺省初始化;
  • if T is an array type, then each element is value-initialized;
  • 如果T是数组类型,则每个元素都是值初始化的;
  • otherwise, the object is zero-initialized
  • 否则,对象是零初始化的

7 To default-initialize an object of type T means:

7 .默认初始化类型为T的对象意味着:

  • if T is a (possibly cv-qualified) class type (Clause 9), the default constructor (12.1) for T is called (and the initialization is ill-formed if T has no default constructor or overload resolution (13.3) results in an ambiguity or in a function that is deleted or inaccessible from the context of the initialization);
  • 如果T是一个(可能cv-qualified)类类型(条款9),T的默认构造函数(12.1)称为(初始化是不规范的,如果T没有默认的构造函数或重载解析(13.3)结果的歧义或在一个函数中删除或无法从上下文初始化);
  • if T is an array type, each element is default-initialized;
  • 如果T是数组类型,则每个元素都是默认初始化的;
  • otherwise, no initialization is performed.
  • 否则,不会执行初始化。

6 To zero-initialize an object or reference of type T means:

6到零初始化一个对象或类型T的引用意味着:

  • if T is a scalar type (3.9), the object is initialized to the value obtained by converting the integer literal 0 (zero) to T;
  • 如果T是一个标量类型(3.9),则该对象被初始化为通过将整数值0(0)转换为T所获得的值;
  • if T is a (possibly cv-qualified) non-union class type, each non-static data member and each base-class subobject is zero-initialized and padding is initialized to zero bits;
  • 如果T是(可能是cv限定的)非联合类类型,则每个非静态数据成员和每个基类子对象都是零初始化的,填充被初始化为零位;
  • if T is a (possibly cv-qualified) union type, the object’s first non-static named data member is zero-initialized and padding is initialized to zero bits;
  • 如果T是(可能是cv限定的)联合类型,则对象的第一个非静态命名数据成员为零初始化,填充被初始化为零位;
  • if T is an array type, each element is zero-initialized;
  • 如果T是一个数组类型,那么每个元素都是零初始化的;
  • if T is a reference type, no initialization is performed.
  • 如果T是引用类型,则不执行初始化。

§13.3.1.7 Initialization by list-initialization [over.match.list]

由list-initialization§13.3.1.7初始化(over.match.list)

1 When objects of non-aggregate class type T are list-initialized (8.5.4), overload resolution selects the constructor in two phases:

1非聚合类类型T的对象初始化列表(8.5.4)时,重载解析分两个阶段选择构造函数:

  • Initially, the candidate functions are the initializer-list constructors (8.5.4) of the class T and the argument list consists of the initializer list as a single argument.
  • 最初,候选函数是类T的initializer-list构造函数(8.5.4),而参数列表由初始化列表作为单个参数组成。
  • If no viable initializer-list constructor is found, overload resolution is performed again, where the candidate functions are all the constructors of the class T and the argument list consists of the elements of the initializer list.
  • 如果没有找到可行的initializer-list构造函数,则再次执行重载解析,其中候选函数是类T的所有构造函数,而参数列表由初始化器列表的元素组成。

If the initializer list has no elements and T has a default constructor, the first phase is omitted. [...]

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

#2


3  

A pedestrian approach is possible, if you control the class of arg. Use a conversion constructor overloaded for an enum:

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

// 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);
};

Now foo can be:

现在foo可以:

void foo(a_really_long_type_name arg = dflval);

If you can apply this, a benefit is portability; this should work fine in a twenty-five-year-old C++ compiler.

如果你能应用这个,好处就是可移植性;这在一个已有25年历史的c++编译器中应该可以很好地工作。

Multiple classes can all share this dfl enum and its dflval-flavored zero; it's like having a new keyword.

多个类都可以共享这个dfl enum及其dflver风格的zero;就像有了一个新的关键字。

Because an enum is a distinct type, this doesn't interfere with constructor overloads for integer types or characters and so on.

因为enum是一种独特的类型,所以它不会干扰构造函数重载整数类型或字符,等等。

The downside is working it into some classes which already have default construction provided via argument defaulting, which leads to duplicate constructor code.

缺点是将它转换为一些类,这些类已经通过参数默认提供了默认构造,这会导致重复的构造函数代码。

#1


55  

Yes:

是的:

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

To sum up the following standard definitions:

总结以下标准定义:

This is list initialization. Depending of the type, aggregate initialization is performed or the object is value initialized, which in turn implies default initialized or zero initialized.

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

Some "corner" cases are when the type is a specialization of std::initializer_list or when the type has a std::initializer_list constructor (it is called if it has no default constructor)

有些“拐角”情况是当类型是std::initializer_list的专门化时,或者当类型具有std:::initializer_list构造函数时(如果没有默认构造函数,则调用它)


The relevant standard quotes (in order we encounter definitions):

相关的标准引号(按我们遇到定义的顺序):

§8.3.6 Default arguments [dcl.fct.default]

§求值默认参数(dcl.fct.default)

1 If an initializer-clause is specified in a parameter-declaration this initializer-clause is used as a default argument

如果参数声明中指定了initializer-子句,则将该initializer-子句用作默认参数

5 The default argument has the same semantic constraints as the initializer in a declaration of a variable of the parameter type, using the copy-initialization semantics (8.5)

5默认参数具有与参数类型变量声明中的初始化器相同的语义约束,使用复制初始化语义(8.5)

§8.5.4 List-initialization [dcl.init.list]

§8.5.4 List-initialization[dcl.init.list]

1 List-initialization is initialization of an object or reference from a braced-init-list. Such an initializer is called an initializer list, [...]. An initializer list may be empty. List-initialization can occur in direct-initialization or copy initialization contexts; [..] list-initialization in a copy-initialization context is called copy-list-initialization.

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

3 List-initialization of an object or reference of type T is defined as follows:

对于T类型的对象或引用的列表初始化定义如下:

  • If T is an aggregate, aggregate initialization is performed (8.5.1)
  • 如果T是一个聚合,则执行聚合初始化(8.5.1)
  • Otherwise, if the initializer list has no elements and T is a class type with a default constructor, the object is value-initialized.
  • 否则,如果初始化器列表没有元素,而T是带有默认构造函数的类类型,则该对象是值初始化的。
  • Otherwise, if T is a specialization of std::initializer_list, a prvalue initializer_list object is constructed as described below and used to initialize the object according to the rules for initialization of an object from a class of the same type (8.5).
  • 否则,如果T是std的专门化::initializer_list,将构造一个prvalue initializer_list对象,并根据该对象的初始化规则对对象进行初始化(8.5)。
  • Otherwise, if T is a class type, constructors are considered. The applicable constructors are enumerated and the best one is chosen through overload resolution (13.3, 13.3.1.7) [...]
  • 否则,如果T是类类型,则考虑构造函数。列出适用的构造函数,通过重载解析(13.3,13.3.1.7)[…]
  • ...
  • Otherwise, if the initializer list has no elements, the object is value-initialized.
  • 否则,如果初始化器列表没有元素,那么对象就是value-initialized。

§ 8.5 Initializers [dcl.init]

§8.5初始化(dcl.init)

8 To value-initialize an object of type T means:

8对值初始化类型为T的对象意味着:

  • if T is a (possibly cv-qualified) class type (Clause 9) with either no default constructor (12.1) or a default constructor that is user-provided or deleted, then the object is default-initialized;
  • 如果T是一个(可能是cv限定的)类类型(第9条),没有默认构造函数(12.1)或默认构造函数(用户提供或删除),则对象是默认初始化的;
  • if T is a (possibly cv-qualified) class type without a user-provided or deleted default constructor, then the object is zero-initialized and the semantic constraints for default-initialization are checked, and if T has a non-trivial default constructor, the object is default-initialized;
  • 如果T是一个(可能是cv限定的)类类型,没有用户提供的或删除的默认构造函数,则对象为零初始化,检查默认初始化的语义约束,如果T有一个非平凡的默认构造函数,则对象为缺省初始化;
  • if T is an array type, then each element is value-initialized;
  • 如果T是数组类型,则每个元素都是值初始化的;
  • otherwise, the object is zero-initialized
  • 否则,对象是零初始化的

7 To default-initialize an object of type T means:

7 .默认初始化类型为T的对象意味着:

  • if T is a (possibly cv-qualified) class type (Clause 9), the default constructor (12.1) for T is called (and the initialization is ill-formed if T has no default constructor or overload resolution (13.3) results in an ambiguity or in a function that is deleted or inaccessible from the context of the initialization);
  • 如果T是一个(可能cv-qualified)类类型(条款9),T的默认构造函数(12.1)称为(初始化是不规范的,如果T没有默认的构造函数或重载解析(13.3)结果的歧义或在一个函数中删除或无法从上下文初始化);
  • if T is an array type, each element is default-initialized;
  • 如果T是数组类型,则每个元素都是默认初始化的;
  • otherwise, no initialization is performed.
  • 否则,不会执行初始化。

6 To zero-initialize an object or reference of type T means:

6到零初始化一个对象或类型T的引用意味着:

  • if T is a scalar type (3.9), the object is initialized to the value obtained by converting the integer literal 0 (zero) to T;
  • 如果T是一个标量类型(3.9),则该对象被初始化为通过将整数值0(0)转换为T所获得的值;
  • if T is a (possibly cv-qualified) non-union class type, each non-static data member and each base-class subobject is zero-initialized and padding is initialized to zero bits;
  • 如果T是(可能是cv限定的)非联合类类型,则每个非静态数据成员和每个基类子对象都是零初始化的,填充被初始化为零位;
  • if T is a (possibly cv-qualified) union type, the object’s first non-static named data member is zero-initialized and padding is initialized to zero bits;
  • 如果T是(可能是cv限定的)联合类型,则对象的第一个非静态命名数据成员为零初始化,填充被初始化为零位;
  • if T is an array type, each element is zero-initialized;
  • 如果T是一个数组类型,那么每个元素都是零初始化的;
  • if T is a reference type, no initialization is performed.
  • 如果T是引用类型,则不执行初始化。

§13.3.1.7 Initialization by list-initialization [over.match.list]

由list-initialization§13.3.1.7初始化(over.match.list)

1 When objects of non-aggregate class type T are list-initialized (8.5.4), overload resolution selects the constructor in two phases:

1非聚合类类型T的对象初始化列表(8.5.4)时,重载解析分两个阶段选择构造函数:

  • Initially, the candidate functions are the initializer-list constructors (8.5.4) of the class T and the argument list consists of the initializer list as a single argument.
  • 最初,候选函数是类T的initializer-list构造函数(8.5.4),而参数列表由初始化列表作为单个参数组成。
  • If no viable initializer-list constructor is found, overload resolution is performed again, where the candidate functions are all the constructors of the class T and the argument list consists of the elements of the initializer list.
  • 如果没有找到可行的initializer-list构造函数,则再次执行重载解析,其中候选函数是类T的所有构造函数,而参数列表由初始化器列表的元素组成。

If the initializer list has no elements and T has a default constructor, the first phase is omitted. [...]

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

#2


3  

A pedestrian approach is possible, if you control the class of arg. Use a conversion constructor overloaded for an enum:

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

// 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);
};

Now foo can be:

现在foo可以:

void foo(a_really_long_type_name arg = dflval);

If you can apply this, a benefit is portability; this should work fine in a twenty-five-year-old C++ compiler.

如果你能应用这个,好处就是可移植性;这在一个已有25年历史的c++编译器中应该可以很好地工作。

Multiple classes can all share this dfl enum and its dflval-flavored zero; it's like having a new keyword.

多个类都可以共享这个dfl enum及其dflver风格的zero;就像有了一个新的关键字。

Because an enum is a distinct type, this doesn't interfere with constructor overloads for integer types or characters and so on.

因为enum是一种独特的类型,所以它不会干扰构造函数重载整数类型或字符,等等。

The downside is working it into some classes which already have default construction provided via argument defaulting, which leads to duplicate constructor code.

缺点是将它转换为一些类,这些类已经通过参数默认提供了默认构造,这会导致重复的构造函数代码。