什么是微不足道的功能?

时间:2015-05-10 14:40:52

标签: c++ language-lawyer c++14

[basic.def.odr] / 3引用术语“非平凡函数”,其定义在标准(N4140)中找不到。

[basic.def.odr] / 3

  

变量x,其名称显示为可能已评估的表达式   ex除非应用左值到右值的转换,否则由ex使用   (4.1)到x产生一个不调用的常量表达式(5.19)   任何非平凡的函数,如果x是一个对象,ex是一个元素   表达式e的潜在结果集,其中任何一个   左值到左值的转换(4.1)适用于e,或e是a   丢弃值表达式(第5条)。

2 个答案:

答案 0 :(得分:7)

“非平凡功能”是“琐碎的特殊成员功能”的补充。有一些关于什么是普通的和非平凡的默认/复制/移动构造函数,复制/移动赋值运算符或析构函数的定义 - 仅属于特殊成员函数的特征,并决定是否例如在某些情况下需要调用它们。

这些的定义可以在章节§12中找到。

默认构造函数,§12.1/ 4:

  

默认构造函数是琐事,如果它不是用户提供的,如果:

     
      
  • 其类没有虚函数(10.3),没有虚基类(10.1)和
  •   
  • 其类的非静态数据成员没有括号或等于初始化程序,
  •   
  • 其类的所有直接基类都有简单的默认构造函数和
  •   
  • 对于类类的所有非静态数据成员(或其数组),每个类都有一个普通的默认值   构造
  •   
     

否则,默认构造函数是非平凡

复制/移动构造函数,§12.8/ 12:

  

如果不是,则类X的复制/移动构造函数琐碎   用户提供的,其参数类型列表等同于   参数类型列表的隐式声明,如果

     
      
  • class X没有虚函数(10.3),没有虚基类(10.1),
  •   
  • class X没有volatile限定类型的非静态数据成员,
  •   
  • 选择复制/移动每个直接基类子对象的构造函数是微不足道的,
  •   
  • 对于类型(或其数组)的X的每个非静态数据成员,选择复制/移动该成员的构造函数是   琐碎;
  •   
     

否则复制/移动构造函数非平凡

复制/移动赋值运算符,§12.8/ 26:

  

X的复制/移动赋值运算符琐事如果是   不是用户提供的,它的 parameter-type-list 等同于   参数类型列表的隐式声明,如果

     
      
  • class X没有虚函数(10.3),没有虚基类(10.1),
  •   
  • class X没有volatile限定类型的非静态数据成员,
  •   
  • 选择复制/移动每个直接基类的赋值运算符
  •   
  • 对于类{(1)类的每个非静态数据成员(或其数组),选择赋值运算符来复制/移动该类   会员很琐碎;
  •   
     

否则复制/移动赋值运算符非平凡

析构函数,§12.4/ 5:

  

如果析构函数不是用户提供的,则析构函数是琐事,如果:

     
      
  • 析构函数不是虚拟的,
  •   
  • 其类的所有直接基类都有简单的析构函数,
  •   
  • 对于类类的所有非静态数据成员(或其数组),每个类都有一个小问题   析构函数。
  •   
     

否则,析构函数非平凡

答案 1 :(得分:0)

可能是这个小例子将帮助你理解[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(); 
      } 

如果您查看标准

中的以下行

将lvalue-to-rvalue转换(4.1)应用于x会产生一个不调用任何重要函数的常量表达式(5.19)

这里c满足出现在常量表达式中的要求, 但是将lvalue-to-rvalue转换应用于a 非平凡的功能。

为什么它会调用一个非平凡的函数?

当在未评估的操作数或其子表达式中发生左值到右值转换时,不会访问引用对象中包含的值。否则,如果glvalue具有类类型,则转换从glvalue初始化类型T的临时值,转换结果是临时

的prvalue

因此使用类C的复制构造函数创建prvalue,因为复制构造函数是用户声明的,它是非平凡的,因此c不是在这里使用ODR

如果不是用户提供的,则类X的复制/移动赋值运算符是微不足道的,其参数类型列表等效于隐式声明的参数类型列表

我希望这个例子澄清你的怀疑