什么是平凡的功能?
What is a trivial function?
[basic.def.odr]/3 引用了术语 "nontrivial function",我在标准 (N4140) 中找不到其定义。
[basic.def.odr]/3
A variable x whose name appears as a potentially-evaluated expression
ex is odr-used by ex unless applying the lvalue-to-rvalue conversion
(4.1) to x yields a constant expression (5.19) that does not invoke
any nontrivial functions and, if x is an object, ex is an element of
the set of potential results of an expression e, where either the
lvalue-to-rvalue conversion (4.1) is applied to e, or e is a
discarded-value expression (Clause 5).
"non-trivial function"是"trivial special member function"的补码。对于什么是平凡的和非平凡的 default/copy/move 构造函数,copy/move 赋值运算符或析构函数有定义 - 仅适用于特殊成员函数的特征,并决定是否例如。这些需要在某些情况下调用。
这些的定义可以在第 12 章中找到。
默认构造函数, §12.1/4:
A default constructor is trivial if it is not user-provided and if:
- its class has no virtual functions (10.3) and no virtual base classes (10.1), and
- no non-static data member of its class has a brace-or-equal-initializer, and
- all the direct base classes of its class have trivial default constructors, and
- for all the non-static data members of its class that are of class type (or array thereof), each such class has a trivial default
constructor.
Otherwise, the default constructor is non-trivial.
Copy/move 构造函数, §12.8/12:
A copy/move constructor for class X is trivial if it is not
user-provided, its parameter-type-list is equivalent to the
parameter-type-list of an implicit declaration, and if
- class
X
has no virtual functions (10.3) and no virtual base classes (10.1), and
- class
X
has no non-static data members of volatile-qualified type, and
- the constructor selected to copy/move each direct base class subobject is trivial, and
- for each non-static data member of
X
that is of class type (or array thereof), the constructor selected to copy/move that member is
trivial;
otherwise the copy/move constructor is non-trivial.
Copy/move 赋值运算符, §12.8/26:
A copy/move assignment operator for class X
is trivial if it is
not user-provided, its parameter-type-list is equivalent to the
parameter-type-list of an implicit declaration, and if
- class
X
has no virtual functions (10.3) and no virtual base classes (10.1), and
- class
X
has no non-static data members of volatile-qualified type, and
- the assignment operator selected to copy/move each direct base class
- for each non-static data member of
X
that is of class type (or array thereof), the assignment operator selected to copy/move that
member is trivial;
otherwise the copy/move assignment operator is non-trivial.
析构函数, §12.4/5:
A destructor is trivial if it is not user-provided and if:
- the destructor is not virtual,
- all of the direct base classes of its class have trivial destructors, and
- for all of the non-static data members of its class that are of class type (or array thereof), each such class has a trivial
destructor.
Otherwise, the destructor is non-trivial
可能是这个小例子将帮助您理解 [basic.def.odr]/3
上下文中的非平凡函数
struct C {
int l;
constexpr C(int _l) : l(_l) { }
constexpr C(const C&c) : q(c.l* 2) { }
};
int main(void) {
constexpr C c(42);
constexpr int m= c.l;
struct K{
int foo() { return c.l; }
} l;
return l.foo();
}
如果您查看标准中的以下行
将左值到右值转换 (4.1) 应用于 x 会产生一个不调用任何非平凡函数的常量表达式 (5.19)
这里c满足出现在常量表达式中的要求,
但是将左值到右值转换应用于 a 会调用 a
非平凡的功能。
为什么它会调用一个非平凡的函数?
当在未计算的操作数或其子表达式中发生左值到右值的转换时,不会访问引用对象中包含的值。否则,如果 glvalue 具有 class 类型,则转换从 glvalue 复制初始化类型 T 的临时值,并且转换的结果是临时值
的纯右值
因此使用 class C 的复制构造函数创建了一个纯右值,并且由于复制构造函数是用户声明的,它是非平凡的,因此 c 在此处未使用 ODR
A copy/move 赋值运算符对于 class X 是微不足道的,如果它不是用户提供的,它的参数类型列表等同于参数类型列表隐式声明
我希望这个例子能澄清你的疑问
[basic.def.odr]/3 引用了术语 "nontrivial function",我在标准 (N4140) 中找不到其定义。
[basic.def.odr]/3
A variable x whose name appears as a potentially-evaluated expression ex is odr-used by ex unless applying the lvalue-to-rvalue conversion (4.1) to x yields a constant expression (5.19) that does not invoke any nontrivial functions and, if x is an object, ex is an element of the set of potential results of an expression e, where either the lvalue-to-rvalue conversion (4.1) is applied to e, or e is a discarded-value expression (Clause 5).
"non-trivial function"是"trivial special member function"的补码。对于什么是平凡的和非平凡的 default/copy/move 构造函数,copy/move 赋值运算符或析构函数有定义 - 仅适用于特殊成员函数的特征,并决定是否例如。这些需要在某些情况下调用。
这些的定义可以在第 12 章中找到。
默认构造函数, §12.1/4:
A default constructor is trivial if it is not user-provided and if:
- its class has no virtual functions (10.3) and no virtual base classes (10.1), and
- no non-static data member of its class has a brace-or-equal-initializer, and
- all the direct base classes of its class have trivial default constructors, and
- for all the non-static data members of its class that are of class type (or array thereof), each such class has a trivial default constructor.
Otherwise, the default constructor is non-trivial.
Copy/move 构造函数, §12.8/12:
A copy/move constructor for class X is trivial if it is not user-provided, its parameter-type-list is equivalent to the parameter-type-list of an implicit declaration, and if
- class
X
has no virtual functions (10.3) and no virtual base classes (10.1), and- class
X
has no non-static data members of volatile-qualified type, and- the constructor selected to copy/move each direct base class subobject is trivial, and
- for each non-static data member of
X
that is of class type (or array thereof), the constructor selected to copy/move that member is trivial;otherwise the copy/move constructor is non-trivial.
Copy/move 赋值运算符, §12.8/26:
A copy/move assignment operator for class
X
is trivial if it is not user-provided, its parameter-type-list is equivalent to the parameter-type-list of an implicit declaration, and if
- class
X
has no virtual functions (10.3) and no virtual base classes (10.1), and- class
X
has no non-static data members of volatile-qualified type, and- the assignment operator selected to copy/move each direct base class
- for each non-static data member of
X
that is of class type (or array thereof), the assignment operator selected to copy/move that member is trivial;otherwise the copy/move assignment operator is non-trivial.
析构函数, §12.4/5:
A destructor is trivial if it is not user-provided and if:
- the destructor is not virtual,
- all of the direct base classes of its class have trivial destructors, and
- for all of the non-static data members of its class that are of class type (or array thereof), each such class has a trivial destructor.
Otherwise, the destructor is non-trivial
可能是这个小例子将帮助您理解 [basic.def.odr]/3
上下文中的非平凡函数struct C {
int l;
constexpr C(int _l) : l(_l) { }
constexpr C(const C&c) : q(c.l* 2) { }
};
int main(void) {
constexpr C c(42);
constexpr int m= c.l;
struct K{
int foo() { return c.l; }
} l;
return l.foo();
}
如果您查看标准中的以下行
将左值到右值转换 (4.1) 应用于 x 会产生一个不调用任何非平凡函数的常量表达式 (5.19)
这里c满足出现在常量表达式中的要求, 但是将左值到右值转换应用于 a 会调用 a 非平凡的功能。
为什么它会调用一个非平凡的函数?
当在未计算的操作数或其子表达式中发生左值到右值的转换时,不会访问引用对象中包含的值。否则,如果 glvalue 具有 class 类型,则转换从 glvalue 复制初始化类型 T 的临时值,并且转换的结果是临时值
的纯右值因此使用 class C 的复制构造函数创建了一个纯右值,并且由于复制构造函数是用户声明的,它是非平凡的,因此 c 在此处未使用 ODR
A copy/move 赋值运算符对于 class X 是微不足道的,如果它不是用户提供的,它的参数类型列表等同于参数类型列表隐式声明
我希望这个例子能澄清你的疑问