我对C ++中的实例化有点困惑。考虑以下代码(在VC ++ 2012下编译正常):
struct Foo;
template <class T> Foo* Create() { return new Foo; }
Foo* MyFoo = Create<int>();
// (A) I expected point of instantiation to be here
struct Foo {};
// (B) But it appears to be here instead
我期望实例化的点是上面的点(A),但显然不是这种情况(因为Foo在点(A)处是不完整的类型)。任何人都可以解释为什么这个编译?这是标准行为还是MSVC的怪癖?
编辑:为了澄清,我真正想知道的是:这是一个有效的程序吗?编译器是否应该接受它,为什么? (显然,如果编译器接受该程序而不应该接受该程序,那么这是MSVC的不符合行为。)
答案 0 :(得分:2)
让我们从顶部开始吧。 Create()
的定义无效,因为它试图为正文中的不完整类型分配内存。但是,您可以在此处声明此函数并在以后定义它。
Create<int>()
的声明很好 - 允许声明指向不完整类型的指针,或允许返回一个的函数。
当然,如果从代码末尾删除Foo的定义,编译器就会到达最后并意识到它从未看到过Foo类型的定义。然后,不是在定义之前的不完整类型,而是Foo结构只是未定义的,任何引用它的代码都将无法编译。
程序无效(尝试定义分配不完整类型的函数)
struct Foo;
template <class T> Foo* Create() { return new Foo; }
Foo* MyFoo = Create<int>();
struct Foo {};
程序的有效版本(移动分配Foo的函数定义到最后):
struct Foo;
template <class T> Foo* Create();
Foo* MyFoo = Create<int>();
struct Foo {};
template <class T> Foo* Create() { return new Foo; }
该程序在g ++下编译,据我所知是完全允许的。 标准的相关部分:
<强> 5.3.1p1 强> “通过指向不完整类型(cv void除外)的指针的间接是有效的。这样获得的左值可以以有限的方式使用(例如,初始化引用);此左值不能转换为prvalue”
<强> 8.3.5p9 强> “不应在返回或参数类型中定义类型。函数定义的参数类型或返回类型不应是不完整的类类型”