删除所有构造函数(或其他函数)的最佳样式?

gla*_*erl 9 c++ memory-management delete-operator c++11

假设我想制作一个无法构造的类型(不要问为什么).

struct Impossible
{
Run Code Online (Sandbox Code Playgroud)

我可以这样做:

    Impossible() = delete;
    // disable automatically generated constructors, don't declare any others
    Impossible(const Impossible&) = delete;
    // I suppose this is redundant with nothing to copy
Run Code Online (Sandbox Code Playgroud)

或者像这样:

    Impossible(...) = delete;
    // explicitly disable all constructors
Run Code Online (Sandbox Code Playgroud)

或者像这样:

    template<typename... Ts>
    Impossible(Ts...) = delete;
    // explicitly disable all constructors, template version
};
Run Code Online (Sandbox Code Playgroud)

我想我可以对任何函数提出同样的问题,而不仅仅是构造函数.

我选择哪一个有什么不同?在语法方面,我认为我喜欢第二种选择.但是,在任何情况下,是否有可能检测到差异(除了错误信息的文本中)?

Luc*_*ore 8

第一个是绰绰有余 - 编译器不会生成构造函数,而且最重要的是,它是惯用的.


Naw*_*waz 5

您不能创建此类的实例:

struct Impossible
{
    Impossible() = delete;
};
Run Code Online (Sandbox Code Playgroud)

请注意复制构造函数(或移动构造函数)的问题甚至不会出现,因此删除它们是不必要的。一个对象不能存在,因为它不能被构造,所以复制或移动是没有问题的。


Jon*_*ely 5

有区别,例如:

#include <type_traits>

struct Unconstructible
{
    Unconstructible() = delete;
};

static_assert( !std::is_default_constructible<Unconstructible>::value, "not default constructible" );
static_assert( std::is_copy_constructible<Unconstructible>::value, "copyable" );
Run Code Online (Sandbox Code Playgroud)

虽然你永远不能构造这个对象,但实际上你根本不能创建一个副本,根据库中的语言和类型特征,它在技术上是CopyConstructible,因为它有一个隐式声明的拷贝构造函数.

类似地,使用Impossible(...)Impossible(Ts&&...)表单仍然存在隐式声明的复制构造函数.

另一方面,如果你这样做:

#include <type_traits>

struct Unconstructible
{
    Unconstructible(const Unconstructible&) = delete;
};

static_assert( !std::is_default_constructible<Unconstructible>::value, "not default constructible" );
static_assert( !std::is_copy_constructible<Unconstructible>::value, "not copyable" );
Run Code Online (Sandbox Code Playgroud)

用户声明的构造函数的存在会抑制默认构造函数的隐式声明,因此该类既不是DefaultConstructible也不是CopyConstructible.


注意你的最后一个例子应该是Impossible(Ts&&...)匹配任何类型,包括不可复制和不可移动的类型.

  • 是.[class.copy]/2 _类`X`的非模板构造函数是一个复制构造函数,如果它的第一个参数是`X&`,`const X&`,`volatile X&`或`const volatile X&`,或者是没有其他参数,或者所有其他参数都有默认参数._ [class.copy]/7 _如果类定义没有显式声明一个复制构造函数,则会隐式声明一个.所以更通用的构造函数在技术上不是"复制构造函数",即使它可以用于复制类型. (2认同)