c++ - 为什么我的类不可默认构造?

标签 c++ nsdmi

我有这些类(class):

#include <type_traits>

template <typename T>
class A {
public:
    static_assert(std::is_default_constructible_v<T>);

};

struct B {
   struct C {
      int i = 0;
   };

    A<C> a_m;
};

int main() {
    A<B::C> a;
}

编译时,a_m不是默认可构造的,但 a是。

更改时C到:
struct C {
      int i;
   };

一切安好。

使用 Clang 9.0.0 测试。

最佳答案

标准文本和评论中指出的几个主要实现都不允许这样做,但出于完全不相关的原因。

一、“by the book”原因:A<C>的实例化点是,根据标准,immediately before the definition of B ,以及 std::is_default_constructible<C> 的实例化点在此之前:

For a class template specialization, [...] if the specialization is implicitly instantiated because it is referenced from within another template specialization, if the context from which the specialization is referenced depends on a template parameter, and if the specialization is not instantiated previous to the instantiation of the enclosing template, the point of instantiation is immediately before the point of instantiation of the enclosing template. Otherwise, the point of instantiation for such a specialization immediately precedes the namespace scope declaration or definition that refers to the specialization.



C在这一点上显然是不完整的,实例化 std::is_default_constructible<C> 的行为未定义。但是,请参阅 core issue 287 ,这将改变这个规则。

实际上,这与 NSDMI 有关。
  • NSDMI 很奇怪,因为它们会延迟解析——或者用标准的说法,它们是一个“完整类上下文”。
  • 因此,该 = 0原则上可以引用B中的东西尚未声明,因此实现无法真正尝试解析它,直到它完成 B .
  • 完成一个类需要隐式声明特殊的成员函数,尤其是默认构造函数,如 C没有声明构造函数。
  • 该声明的一部分(constexpr-ness、noexcept-ness)取决于 NSDMI 的属性。
  • 因此,如果编译器不能解析 NSDMI,它就不能完成类。
  • 结果,在它实例化 A<C> 时,它认为C不完整。

  • 整个处理延迟解析区域的区域都没有详细说明,伴随着实现的分歧。可能需要一段时间才能清理干净。

    关于c++ - 为什么我的类不可默认构造?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60307207/

    相关文章:

    c++ - C 中的 Ruby 添加到 $LOAD_PATH

    c++ - 绘制线条时关闭openGL中的颜色插值

    c++ - 我的代码通过了测试用例,但是在我提交时显示了错误的答案

    c++ - Makefile/C++ 类 : Makefile error for C++? 或者类定义错误?

    c++ - 访问静态和非静态的模板构造函数和函数

    c++ - 为什么默认构造性对于使用 NSDMI 的内部结构会表现得很奇怪?