【问题标题】:Are the special member functions always declared?是否总是声明特殊成员函数?
【发布时间】:2012-01-27 12:34:47
【问题描述】:

在标准的第 12 节中,每个特殊的成员函数都有一组规则使其成为 implicitly declared as defaulted 和另一组规则导致 a defaulted [special member function to be] defined as deleted

这使得(在我看来)当特殊成员函数没有用户声明的版本时存在 3 种潜在状态:已声明和已定义 (defaulted)、已声明和未定义 (deleted) 和未声明.这是准确的吗?如果是这样,与删除“未声明”选项相比,还有什么意义?

* declared as defaulted 好像是个错误,不应该被“定义”为默认吗?

【问题讨论】:

  • @downvoter 为什么?让我知道,以便我修复它。
  • 我现在只有 N3290 可以阅读,相关的地方是 8.4.2 和 8.4.3。您指的是草案还是最终发布的标准?
  • 第12章特殊成员函数[特殊]。在 n3242 中

标签: c++ c++11


【解决方案1】:

已删除的构造函数和隐式未声明的构造函数的区别在于,已删除的构造函数参与重载决议,而不存在的构造函数不参与重载决议。

例子:

这个类是默认可构造的。编译器不会为它隐式声明一个默认的构造函数。

struct A
{
    template <class ...T>
    A(T...) {}
};

int main()
{
    A a;  // ok
}

如果编译器确实为它声明了一个默认构造函数,并且如果该默认构造函数被定义为已删除,那么A 将不是默认可构造的。可以通过以下方式模拟:

struct A
{
    A() = delete;  // pretend the compiler implicitly declared and defined this

    template <class ...T>
    A(T...) {}
};

int main()
{
    A a;
}

error: call to deleted constructor of 'A'
    A a;
      ^

移动构造函数也会出现类似的问题。如果编译器决定隐式声明它并将其定义为已删除,那么即使它具有可行的复制构造函数,也不能从右值构造这样的类:

#include <type_traits>

struct A
{
    A();
    A(const A&);
    A(A&&) = delete;  // pretend compiler declared and defined
};

int main()
{
    A a = std::declval<A>();
}

error: call to deleted constructor of 'A'
    A a = std::declval<A>();
      ^   ~~~~~~~~~~~~~~~~~

但是如果编译器没有隐式声明一个已删除的移动构造函数,那么一切正常:

#include <type_traits>

struct A
{
    A();
    A(const A&);
};

int main()
{
    A a = std::declval<A>();  // ok
}

确实,如果编译器确实A 隐式声明了一个已删除的移动构造函数,那么在C++11 中重新编译时将会出现大量损坏的C++98/03 代码! :-)

【讨论】:

    【解决方案2】:

    我不确定我是否同意你的总结:

    基本上有三种状态:User DefinedDeletedCompiler Generated

    • 声明和定义
      • 这意味着用户已在类中明确声明它们并提供定义。
    • 已声明并删除
      • 这意味着用户已明确声明它们已删除(即它们不可用)。
    • 未声明
      • 用户未提供声明(因此无法提供定义)。
        在这种情况下,编译器将生成该方法的一个版本。

    【讨论】:

    • 还有 declared and deleted 的旧方法:declared but not defined - 用户已在类中明确声明它们,但尚未提供定义。
    • @dalle:这不是语言的一部分;这只是等待发生的链接器错误。但是是的,declared private and not defined 是 C++03 等效于 C++11 中的 declared and deleted。 C++11 方式更简洁,因为您不需要添加额外的注释来说明它是故意未定义的(请不要添加定义)。由于它是语言的一部分,因此可以更快地被标记为错误。
    • @LokiAstari 我质疑的 3 个状态是“不存在用户声明的版本时的潜在状态”,它们都属于您的最后一个状态。
    猜你喜欢
    • 2012-07-25
    • 2012-10-14
    • 2017-08-26
    • 2017-10-05
    • 1970-01-01
    • 2011-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多