11

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

struct Impossible
{

我可以这样做:

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

或像这样:

    Impossible(...) = delete;
    // explicitly disable all constructors

或像这样:

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

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

我选择哪一个有什么区别吗?在语法方面,我想我喜欢第二种选择。但是是否有任何情况可以检测到差异(除了错误消息的文本)?

4

3 回答 3

8

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

于 2013-01-03T11:18:42.547 回答
7

有区别,例如:

#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" );

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

同样,使用Impossible(...)orImpossible(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" );

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


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

于 2013-01-03T15:33:05.133 回答
5

您不能创建此类的实例:

struct Impossible
{
    Impossible() = delete;
};

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

于 2013-01-03T11:21:36.487 回答