是否可以实例化具有已删除的构造函数和析构函数的非聚合 [​​=10=]?

Can a non-aggregate class with deleted constructors and destructor be ever instantiated?

考虑以下 class:

template <class T>
class object {
public:
    using type = T;

    object() = delete;
    object(const object&) = delete;
    object(object&&) = delete;
    object& operator=(const object&) = delete;
    object& operator=(object&&) = delete;
    ~object() = delete;

private:
    type value = 0;
};

是否可以通过任何奇怪的技巧实例化类型为 object<int> 的对象(在堆栈上(可能不是)或堆上(可能?)),或者 object<int> 永远存在于任何可以想象的(结构良好且行为明确的)C++17 程序中?

附录:首先我们考虑非格式错误的 NDR programs/non 未定义行为。当且仅当,只有格式错误的 NDR programs/undefined 行为程序可能时,您可以用这样的程序来说明答案。

我不认为这是一个答案(我不是语言律师),只是 post 来自 n4659 的一些发现:

11.6.20: An object whose initialization has completed is deemed to be constructed, even if no constructor of the object’s class is invoked for the initialization. [ Note: Such an object might have been value-initialized or initialized by aggregate initialization (11.6.1) or by an inherited constructor (15.6.3). —end note ]

注释中提到的 3 个选项中,只有第一个适用:

11.6.8: To value-initialize an object of type T means ... (8.1) — if T is a (possibly cv-qualified) class type (Clause 12) with either no default constructor (15.1) or a default constructor that is user-provided or deleted, then the object is default-initialized;

由于删除了默认构造函数:

11.6.7: To default-initialize an object of type T means ... (7.1) — If T is a (possibly cv-qualified) class type (Clause 12), constructors are considered. The applicable constructors are enumerated (16.3.1.3), and the best one for the initializer () is chosen through overload resolution (16.3). The constructor thus selected is called, with an empty argument list, to initialize the object.

由于没有可以调用的构造函数,我认为classobject的实例无法构造

不,不能。来自 [basic.life]

[...] The lifetime of an object of type T begins when:

  • storage with the proper alignment and size for type T is obtained, and

  • if the object has non-vacuous initialization, its initialization is complete,

因此必须进行初始化。我们接着看all the possible initializations.

  1. 如果初始化器是{...},那么就是list-initialized

    • class是non-aggregate,所以不能是aggregate-initialized
    • class没有默认构造函数,所以不能value-initialized被{}
    • class可以是direct-initialized或copy-initialized的{x},通过重载解析调用构造函数
  2. 如果初始化器是(),那么就是value-initialized

  3. 如果初始化器是相同的cv-unqualified类型,则使用初始化器的初始化器表达式代替初始化器

    • 也就是T x = T(T());只是为了default-initializex,没有副本
  4. 如果没有初始化器,那么就是default-initialized

  5. 否则将考虑使用重载决议调用构造函数。

  6. 到value-initialize就是到default-initialize这种情况下的对象。

  7. Default-initialization 在这种情况下调用默认构造函数。

如果你仔细看,在这个列表中只有一种方法可以初始化对象,那就是调用构造函数。由于我们已经删除了所有构造函数,因此我们无法初始化对象。

规则明确,这个对象不能正确初始化。

既然要求如此,那就为您的class创建一个缓冲区,并小心使用它。

template< typename T >
class object_wrapper
{
    std::byte buffer[ sizeof( T ) ];

public:
    auto& inner() { return *reinterpret_cast< T* >( buffer ); }
};

这是一个例子:

int main()
{
    //object< int > o; // impossible

    object_wrapper< object< int > > ow; // wrap the object

    object< int >& o( ow.inner() );     // possible

    o.some_foo();

}