为什么我的班级不是默认可构造的? [英] Why is my class non default-constructible?

查看:87
本文介绍了为什么我的班级不是默认可构造的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有那些课程:

#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 是可实现的。

When compiling, a_m is not default constructible but a is.

更改 C 到:

struct C {
      int i;
   };

一切都很好。

经过测试Clang 9.0.0。

Tested with Clang 9.0.0.

推荐答案

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

This is disallowed both by the text of the standard and by several major implementations as noted in the comments, but for completely unrelated reasons.

首先,按书原因: A< C> 紧接在定义之前 B 的实例,而 std :: is_default_constructible< C> 的实例化点就在此之前。 :

First, the "by the book" reason: the point of instantiation of A<C> is, according to the standard, immediately before the definition of B, and the point of instantiation of std::is_default_constructible<C> is immediately before that:


对于类模板专业化,如果专业化是
隐式实例化的,因为它是从内部引用的,所以[...]另一个
模板专业化,如果引用专业化
的上下文取决于模板参数,如果
专业化没有在封装模板
的实例化之前实例化,则实例化的位置就在封装模板的实例化点之前

否则,这种专业化
的实例化点紧接在引用该专业化的名称空间范围声明或定义
之前。

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>的行为未定义。但是,请参见核心问题287 ,它将更改此规则。

Since C is clearly incomplete at that point, the behavior of instantiating std::is_default_constructible<C> is undefined. However, see core issue 287, which would change this rule.

实际上,这与NSDMI有关。

In reality, this has to do with the NSDMI.


  • NSDMI是奇怪的是,因为它们被延迟解析-或按照标准的说法,它们是完整类上下文。

  • 因此, = 0 原则上可以引用尚未声明的 B 中的内容,因此该实现无法真正尝试解析它,直到它以 B code>。

  • 完成类需要隐式声明特殊成员函数,尤其是默认构造函数,如 C 没有声明构造函数。

  • 该声明的部分(constexpr-ness,noexcept-ness)取决于NSDMI的属性。

  • 因此,如果编译器无法解析NSDMI,则它将无法完成该类。

  • 因此,在实例化时tes A< C> ,它认为 C 是不完整的。

  • NSDMIs are weird because they get delayed parsing - or in standard parlance they are a "complete-class context".
  • Thus, that = 0 could in principle refer to things in B not yet declared, so the implementation can't really try to parse it until it has finished with B.
  • Completing a class necessitates the implicit declaration of special member functions, in particular the default constructor, as C doesn't have a constructor declared.
  • Parts of that declaration (constexpr-ness, noexcept-ness) depend on the properties of the NSDMI.
  • Thus, if the compiler can't parse the NSDMI, it can't complete the class.
  • As a result, at the point when it instantiates A<C>, it thinks that C is incomplete.

整个处理延迟解析区域的区域都严重不足,伴随着实施上的分歧。可能需要一段时间才能清理干净。

This whole area dealing with delayed-parsed regions is woefully underspecified, with accompanying implementation divergence. It may take a while before it gets cleaned up.

这篇关于为什么我的班级不是默认可构造的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆