如果事后定义类型,则实例化具有不完整类型的类模板吗? [英] Is instantiating a class template with an incomplete type ill-formed, if the type is defined afterwards?

查看:87
本文介绍了如果事后定义类型,则实例化具有不完整类型的类模板吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

此代码肯定是格式错误的,因为Foo在实例化点之后是专用的:

This code is surely ill-formed, because Foo is specialized after an instantiation point:

template <typename T>
struct Foo {
    int a;
};

Foo<int> x = { 42 };

template <>
struct Foo<int> {
    const char *a;
};

Foo<int> x = { "bar" };

由于标准的一部分,它的格式不正确.强调了:

It is ill formed because of the part of the standard I've put emphasis:

函数模板,成员函数模板或类模板的成员函数或静态数据成员的专业化可以在转换单元内具有多个实例化点,并且除了上述实例化点之外,对于翻译单元中具有实例化点的任何此类专业化,翻译单元的末尾也被视为实例化点.类模板的专门化在翻译单元中最多具有一个实例化点.任何模板的特化都可以在多个翻译单元中具有实例化点. 如果两个不同的实例化点根据一个定义规则赋予模板专业化不同的含义,则该程序格式错误,无需诊断.

现在,代码格式错误吗?

Now, is this code ill-formed?

struct A;

template <typename> class Foo { };

Foo<A> foo; // note A is incomplete here

struct A {};

如果这样声明Foo,格式错误会改变吗?

Does the ill-formedness change, if Foo declared like this?

struct A;

template <typename T>
struct Foo {
    Foo() {
        new T;
    }
};

Foo<A> foo; // note A is incomplete here

struct A {};

我问了这个问题,因为在

I asked this question, because of the discussion under this question.

注意,这不是重复项.这个问题是关于为什么要编译代码,这个问题是关于它是否格式错误的问题.它们不同,因为格式错误的程序不一定是非编译程序.

Note, this is not a duplicate. That question is about why the code compiles, this question is about whether it is ill-formed. They differ, because an ill-formed program isn't necessarily a non-compiling program.

注意,对于clang和gcc,我的new T示例会编译,而此示例(T作为成员)不会:

Note, with clang and gcc, my example with new T compiles, while this example (T as a member) doesn't:

struct A;

template <typename T>
struct Foo {
    T t;
};

Foo<A> foo; // note A is incomplete here

struct A {};

也许两者都是不健康的,并且仅针对最后一种情况进行诊断?

Maybe both are ill-formed, and diagnostic is given only for this last case?

推荐答案

假设我们只有一个翻译单元

Assuming we only have one translation unit, [temp.point] rules out your quote as a possible source of ill-formedness

类模板的专门化在翻译单元中最多具有一个实例化点.

A specialization for a class template has at most one point of instantiation within a translation unit.

相反,第一个代码段的问题是 [temp.expl.spec]

Instead, the problem with the first snippet is [temp.expl.spec]

如果一个模板,一个成员模板或一个类模板的成员被明确地专门化,则应在首次使用该专门化之前声明该专门化,这将导致在每个翻译单元中进行隐式实例化.发生使用;无需诊断.

If a template, a member template or a member of a class template is explicitly specialized then that specialization shall be declared before the first use of that specialization that would cause an implicit instantiation to take place, in every translation unit in which such a use occurs; no diagnostic is required.

第二个代码段格式正确,不需要模板参数必须具有完整的类型.

The second snippet is well-formed, there is no requirement that template parameters need to have complete type.

第三个代码段格式错误,new T要求T是完整类型.这里的一个小问题是,构造函数的定义在Foo<A> foo;处隐式实例化.如果是,则将代码段更改为

The third snippet is ill-formed, new T requires that T be a complete type. A slight catch here is that the definition of the constructor is implicitly instantiated at Foo<A> foo;. If however, the snippet is changed to

struct A;

template <typename T>
struct Foo {
    Foo() {
        new T;
    }
};

using FooA = Foo<A>;

struct A {};

然后,不会实例化构造函数的定义,因此其格式正确. [temp.inst]

Then the definition of the constructor isn't instantiated and will therefore be well-formed. [temp.inst]

类模板专业化的隐式实例化导致

The implicit instantiation of a class template specialization causes

  • 未删除的类成员函数,成员类,作用域成员枚举,静态数据成员,成员模板和好友的声明的隐式实例化,而不是定义的隐式实例化;和[...]

第四个代码段格式错误,因为成员需要具有完整的类型. [class.mem]

The fourth snippet is ill-formed because members need to have complete type. [class.mem]

非静态数据成员的类型不得为不完整的类型[...]

The type of a non-static data member shall not be an incomplete type [...]

这篇关于如果事后定义类型,则实例化具有不完整类型的类模板吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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