新的不完整类型在包装在模板中时编译

new of incomplete type compiles when wrapped in template

考虑这段代码,有一个明显的编译错误:(1)

struct A;
struct B {
  B() { new A(); } // error: allocation of incomplete type 'A'
};

使用 unique_ptr 也无济于事:(2)

struct A;
struct B {
  B() { std::make_unique<A>(); } // error: due to ~unique_ptr()
};

然后(令我大吃一惊)我发现,这个 编译:(3)

struct A;
struct B {
  B() { std::make_unique<A>(); }
};
struct A {}; // OK, when a definition is added **below**

然后我检查了,这对 new 是否也有帮助 - 没有: (4)

struct A;
struct B {
  B() { new A(); } // error: allocation of incomplete type 'A'
};
struct A {};

我认为它与 templates 有关,事实上:将 new 包装在 template 编译:( 5)

template <typename T> 
T* my_new() { return new T(); } // OK, when wrapped in template
struct A;
struct B {
  B() { my_new<A>(); }
};
struct A {};

为了完整起见,删除 A 的定义会再次引发错误:(6)

template <typename T> 
T* my_new() { return new T(); } // error: allocation of incomplete type 'A'
struct A;
struct B {
  B() { my_new<A>(); }
}; 
// do note: definition of A removed

这是怎么回事?据我理解,编译器必须知道A的size/definition来分配它,因此仅仅声明它, 是不够的。另外我相信,定义必须先于分配。

这似乎是正确的,当直接使用 new (1,4) 时。但是当new换行的时候,很明显是我弄错了(2,3,5,6).

目前我发现的可能的解释是:

为什么 4 被认为是不正确的,而 5 是编译的(或者 5 只是虚假地编译了未定义的行为 [但是 3 一定也有缺陷,对吧?])?

顺便说一句:使用 clang++-3.5.0 和 g++-4.9.2 测试

§14.6.4.1 [temp.point]/p1,8,强调我的:

1 For a function template specialization, a member function template specialization, or a specialization for a member function or static data member of a class template, if the specialization is implicitly instantiated because it is referenced from within another template specialization and the context from which it is referenced depends on a template parameter, the point of instantiation of the specialization is the point of instantiation of the enclosing specialization. Otherwise, the point of instantiation for such a specialization immediately follows the namespace scope declaration or definition that refers to the specialization.

8 A specialization for a function template, a member function template, or of a member function or static data member of a class template may have multiple points of instantiations within a translation unit, and in addition to the points of instantiation described above, for any such specialization that has a point of instantiation within the translation unit, the end of the translation unit is also considered a point of instantiation. A specialization for a class template has at most one point of instantiation within a translation unit. A specialization for any template may have points of instantiation in multiple translation units. If two different points of instantiation give a template specialization different meanings according to the one definition rule (3.2), the program is ill-formed, no diagnostic required.

my_new<A>有两个实例化点,一个在B定义的末尾,一个在翻译单元的末尾。由于这两点将导致不同的含义(对于代码段 3 和 5),该程序是格式错误的 NDR(即,它具有未定义的行为)。