将默认参数值设置为默认构造函数的更好语法
Nicer syntax for setting default argument value to default constructor
可能想要声明一个带参数的函数,并指定参数的默认值是该类型默认构造函数的结果:
void foo(a::really::long::type::name arg = a::really::long::type::name());
是否有更好的语法,不需要输入两次类型名称?类似于:
void foo(a::really::long::type::name arg = default);
我意识到我可以 typedef
类型名称使其更漂亮,但我很好奇是否存在这样的语法。
是:
void foo(a::really::long::type::name arg = {});
总结出以下标准定义:
这是列表初始化。根据类型,执行聚合初始化或对对象进行值初始化,这又意味着默认初始化或零初始化。
一些 "corner" 情况是类型是 std::initializer_list
的特化或类型具有 std::initializer_list
构造函数(如果没有默认构造函数则调用它)
相关标准引述(以我们遇到的顺序定义):
§8.3.6 默认参数 [dcl.fct.default]
1 If an initializer-clause is specified in a parameter-declaration this
initializer-clause is used as a default argument
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)
§8.5.4 列表初始化 [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:
- If T is an aggregate, aggregate initialization is performed (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.
- 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).
- 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) [...]
- ...
- Otherwise, if the initializer list has no elements, the object is value-initialized.
§ 8.5 初始化器 [dcl.init]
8 To value-initialize an object of type T means:
- 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;
- 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;
- if T is an array type, then each element is value-initialized;
- otherwise, the object is zero-initialized
7 To default-initialize an object of type T means:
- 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);
- if T is an array type, each element is default-initialized;
- otherwise, no initialization is performed.
6 To zero-initialize an object or reference of type T means:
- 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;
- 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;
- 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;
- if T is an array type, each element is zero-initialized;
- if T is a reference type, no initialization is performed.
§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:
- 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.
- 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.
If the initializer list has no elements and T has a default
constructor, the first phase is omitted. [...]
如果您控制 arg
的 class,行人接近是可能的。使用为 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);
如果你能应用这个,好处就是可移植性;这在一个有 25 年历史的 C++ 编译器中应该可以正常工作。
多个 classes 都可以共享这个 dfl
enum
和它的 dflval
-flavored 零;就像有了一个新关键字。
因为 enum
是一个独特的类型,这不会干扰整数类型或字符等的构造函数重载。
缺点是将其用于一些 classes 中,这些已经通过参数默认设置提供了默认构造,这会导致重复的构造函数代码。
可能想要声明一个带参数的函数,并指定参数的默认值是该类型默认构造函数的结果:
void foo(a::really::long::type::name arg = a::really::long::type::name());
是否有更好的语法,不需要输入两次类型名称?类似于:
void foo(a::really::long::type::name arg = default);
我意识到我可以 typedef
类型名称使其更漂亮,但我很好奇是否存在这样的语法。
是:
void foo(a::really::long::type::name arg = {});
总结出以下标准定义:
这是列表初始化。根据类型,执行聚合初始化或对对象进行值初始化,这又意味着默认初始化或零初始化。
一些 "corner" 情况是类型是 std::initializer_list
的特化或类型具有 std::initializer_list
构造函数(如果没有默认构造函数则调用它)
相关标准引述(以我们遇到的顺序定义):
§8.3.6 默认参数 [dcl.fct.default]
1 If an initializer-clause is specified in a parameter-declaration this initializer-clause is used as a default argument
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)
§8.5.4 列表初始化 [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:
- If T is an aggregate, aggregate initialization is performed (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.
- 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).
- 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) [...]
- ...
- Otherwise, if the initializer list has no elements, the object is value-initialized.
§ 8.5 初始化器 [dcl.init]
8 To value-initialize an object of type T means:
- 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;
- 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;
- if T is an array type, then each element is value-initialized;
- otherwise, the object is zero-initialized
7 To default-initialize an object of type T means:
- 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);
- if T is an array type, each element is default-initialized;
- otherwise, no initialization is performed.
6 To zero-initialize an object or reference of type T means:
- 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;
- 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;
- 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;
- if T is an array type, each element is zero-initialized;
- if T is a reference type, no initialization is performed.
§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:
- 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.
- 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.
If the initializer list has no elements and T has a default constructor, the first phase is omitted. [...]
如果您控制 arg
的 class,行人接近是可能的。使用为 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);
如果你能应用这个,好处就是可移植性;这在一个有 25 年历史的 C++ 编译器中应该可以正常工作。
多个 classes 都可以共享这个 dfl
enum
和它的 dflval
-flavored 零;就像有了一个新关键字。
因为 enum
是一个独特的类型,这不会干扰整数类型或字符等的构造函数重载。
缺点是将其用于一些 classes 中,这些已经通过参数默认设置提供了默认构造,这会导致重复的构造函数代码。