当前位置: 首页 > 知识库问答 >
问题:

如果类型是事后定义的,实例化具有不完整类型的类模板是否格式不良?

郏经纬
2023-03-14

这段代码的格式肯定不正确,因为foo是在实例化点之后专门化的:

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

Foo<int> x = { 42 };

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

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

由于我强调的标准的一部分,它是不正确的:

函数模板、成员函数模板、或类模板的成员函数或静态数据成员的专门化可以在翻译单元内具有多个实例化点,并且除了上述实例化点之外,对于在翻译单元内具有实例化点的任何这样的专门化,翻译单元的末尾也被认为是实例化点。类模板的专门化在翻译单元中最多有一个实例化点。任何模板的专门化都可能在多个翻译单元中具有实例化点。如果两个不同的实例化点根据一个定义规则赋予一个模板专门化不同的含义,则程序是格式不良的,不需要诊断。

现在,这段代码是否格式不正确?

struct A;

template <typename> class Foo { };

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

struct A {};

如果foo这样声明,格式不良的情况会改变吗?

struct A;

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

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

struct A {};

我问这个问题,是因为这个问题下的讨论。

struct A;

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

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

struct A {};

也许两者都是病态的,诊断只针对最后一个病例?

共有1个答案

洪英豪
2023-03-14
struct A;
template <typename> class Foo { };
Foo<A> foo; // note A is incomplete here
struct A {};

foo只取决于a的名称,而不是它的完整类型。

所以这是很好的形式;但是,这种事情仍然可以在您测试的每个编译器中中断(变得格式不佳)但编译。

首先,我们窃取is_complete。然后我们这样做:

struct A;
template <class T> class Foo {
  enum{ value = is_complete<T>::value };
};
Foo<A> foo; // note A is incomplete here
struct A {};

[...]对于在翻译单元中有实例化点的任何此类专门化,翻译单元的末尾也被视为实例化点。[...]

因为该子句不适用于模板类。在这里,模板类的唯一实例化很好。

现在,如果在另一个文件中有:

struct A {};
Foo<A> foo2;
struct A;
template <class T> class Foo {
  enum{ value = is_complete<T>::value };
};
Foo<A> foo; // note A is incomplete here
struct A {};
Foo<A> foo2; // ill-formed

一个和两个文件versoins几乎肯定会在C++编译器中编译,不会出现错误或警告。

有些编译器甚至会将模板实例从一个编译单元记录到另一个编译单元;foo将具有::value,即使在创建foo2(a)之后也是::false)。其他的则在每个编译单元中有两个不同的foo;它的方法将被标记为内联(并且是不同的),类的大小可能不一致,并且您将得到一系列格式不良的程序问题。

最后,请注意,std中的许多类型要求它们的模板参数在旧版本的C++中是完整的(包括C++11:“17.6.4.8其他函数(...)2.在以下情况下效果是未定义的:(...)特别是--如果在实例化模板组件时使用不完整类型(3.9)作为模板参数,除非该组件特别允许”--从boost不完整容器文档复制)。具体地说,std::vector 过去要求t必须完整。

C++17对std::vector:

[Vector.Overview]/3

这实际上阻碍了一些无用的代码,比如有一个函数类型返回自己类型1的向量。Boost有一个库来解决这个问题。

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

foo ::foo() 的主体仅在“调用时”实例化。因此,在调用foo::foo()之前,t缺少完成没有影响。

Foo<A> foo;

^^将无法使用不完整的编译。

using foo_t = Foo<A>;

^^将编译,并且不会导致任何问题。

using foo_t = Foo<A>;
struct A {};
foo_t foo;

也没问题。当我们试图构造foo_t时,foo_t::foo_t的主体将被实例化,并且所有定义都匹配。

1你能说状态机转换函数吗?

 类似资料:
  • OpenGL定义了C函数来管理资源。我编写了一个简单的包装器来以RAII的方式处理它们。函数对类似于和。但是,也有一些函数对适用于资源数组,例如和。对于前者,我编写了一个简单的类来完成这项工作,对于后者,我编写了另一个处理数组的类。然而,我注意到有时我只使用一个缓冲区或纹理,在那里我不必承担向量的费用,我想如果发布函数在开始时采用大小参数,我会专门化类析构函数,但是... 对于上述SSCCE g树

  • 我有这样的代码 现在,为了打印值,如果T是一个类,我想调用对象的打印函数,但是如果T是一个基本数据类型,我只想使用printf。 那么,如何确定模板类型是基本数据类型还是类?

  • 本文向大家介绍jquery判断类型是不是number类型的实例代码,包括了jquery判断类型是不是number类型的实例代码的使用技巧和注意事项,需要的朋友参考一下 判断获取的数据是不是number类型 以上就是小编为大家带来的jquery判断类型是不是number类型的实例代码全部内容了,希望大家多多支持呐喊教程~

  • 异常:“字符串”类型不是“映射”类型的子类型 这是上面的json,我只想把它放在用户pojo类中的[data]。 但它抛出了上述异常类型。 用户Pojo类 为了清晰起见,我推荐了这个中等规模的网站 但在4个多小时的静脉注射中,我不知道发生了什么。如果要更改用户。从()到字符串,然后就可以了。但我需要将[data]从json解析到用户pojo类。

  • 我是新手。我正在开发一个测验应用程序,并拥有以下三个dart文件: 主要的飞奔 question.dart answer.dart 当我在android studio中的android上运行应用程序时,出现以下错误: ══╡ 小部件库捕获的异常╞═══════════════════════════════════════════ 生成MyApp时引发了以下类型的错误(脏,状态:_MyAppSta

  • 在存储到本地数据库之前,将字符串转换为对象的正确方法是什么? 这是的输出: 我试图将其转换为CreatedBy对象 创造的 这里是我的本地表列 错误