为什么复制构造函数不是仅仅因为有用户定义的析构函数就变得微不足道?

时间:2019-06-06 09:03:29

标签: c++ language-lawyer template-meta-programming typetraits

以下摘录使用Clang-libstdc ++或Clang-libc ++,GCC,它们的许多版本以及该语言自11(14&17)以来的所有三个版本进行编译:

#include <type_traits>

struct HasUserDefinedDestructor {
    ~HasUserDefinedDestructor() {}
};

using HUDD = HasUserDefinedDestructor;

static_assert(not std::is_trivially_move_constructible<HUDD>::value, "");
static_assert(not std::is_trivially_copy_constructible<HUDD>::value, "");

这使我感到惊讶,因为复制仅需要微不足道的操作。

这是编译器/库中的错误吗,还是标准在某个地方说用户定义了析构函数会使复制和移动构造函数变得不那么琐碎?

编辑:为什么这不是默认构造问题的重复: 根据注释,我们知道构造函数的“异常”和琐碎性受到析构函数的异常和琐碎性的影响,但是在知道所有这些特征都相关之前,问题是不同的。遇到这个问题,任何人都可以看到这与之相关

2 个答案:

答案 0 :(得分:1)

is_trivially_constructibledefined as follows(粗体是我的):

  

is_­constructible_­v<T,Args...>true,并且is_­constructible的变量定义(如下定义)已知不会调用不平凡的操作

«在下面定义»是[meta.unary.op]/8

  

当且仅当对于某些发明变量is_­constructible<T, Args...>遵循以下变量定义时,才应满足模板专业化t的谓词条件:

     

T t(declval<Args>()...);

是的,当析构函数不是很简单时,is_trivially_[copy|move]_constructible_vfalse

答案 1 :(得分:1)

[dcl.fct.def.default]/5

  

[...]如果函数是由用户声明而不是显式的,则由用户提供   在其第一个声明中默认或删除。 [...]

因此,给定

struct HasUserDefinedDestructor {
    ~HasUserDefinedDestructor() {}
};

HasUserDefinedDestructor具有用户提供的析构函数。

[class.dtor]/6

  

如果不是用户提供的析构函数,并且如果:[...]

     

否则,析构函数是不平凡的

因此,HasUserDefinedDestructor具有不平凡的析构函数。

[meta.unary.prop]

template <class T, class... Args>
struct is_­trivially_constructible;
     

条件: is_­constructible_­v<T, Args...>trueis_­constructible的变量定义如下所述,是   已知会调用不重要的操作([basic.types,   [特殊]。

     

前提条件: T,并且参数包Args中的所有类型均应为完整类型 cv void ,或未知范围的数组。

template <class T>
struct is_­trivially_copy_­constructible;
     

条件:对于可引用类型T,结果与is_­trivially_­constructible_­v<T, const T&>相同,否则为false

     

前提条件: T应该是完整类型 cv void或未知边界数组。

template <class T>
struct is_­trivially_­move_­constructible;
     

条件:对于可引用类型T,结果与is_­trivially_­constructible_­v<T, T&&>相同,否则为false

     

前提条件: T应该是完整类型 cv void或未知边界数组。

[meta.unary.prop]/8

  

模板专门化的谓词条件   is_­constructible<T, Args...>在且仅当   以下变量定义对于某些已发明的格式将是正确的   变量t

T t(declval<Args>()...);
     

[注意:”这些标记从不解释为函数   宣言。 — 尾注]就像执行访问检查一样   与T和任何Args不相关的上下文中。只有有效性   考虑变量初始化的即时上下文。   [注意:初始化的评估可能会导致   效果,例如类模板专业化的实例化   和功能模板专业化,   隐式定义的函数,等等。这样的副作用不在   “即时上下文”,并可能导致程序被   格式错误。 — 尾注]

即使似乎在定义位置未调用析构函数,也应该使用变量定义“调用”析构函数。因此,std::is_trivially_move_constructible<HUDD>::valuefalse都是std::is_trivially_copy_constructible<HUDD>::value