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

2024-04-01

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

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

Foo<int> x = { 42 };

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

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

它的格式不正确,因为standard http://eel.is/c++draft/temp.point#8我强调了:

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

Now, is this代码格式错误?

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 {};

我问这个问题是因为下面的讨论question https://stackoverflow.com/questions/52180744/pimpl-why-can-make-unique-be-called-on-an-incomplete-type.

请注意,这不是重复的。这个问题是关于代码为什么可以编译,这个问题是关于代码是否格式错误。它们有所不同,因为格式错误的程序不一定是不可编译的程序。


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

struct A;

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

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

struct A {};

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


struct A;
template <typename> class Foo { };
Foo<A> foo; // note A is incomplete here
struct A {};

Foo<A>仅取决于名称A不是它的完整类型。

所以这是格式良好的;然而,这种事情仍然可能会破坏(变得格式错误),但在您测试的每个编译器中都可以编译。

首先,我们偷做完了 https://stackoverflow.com/a/21121104/1774667。然后我们这样做:

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

你的代码很好。有一个实例化点Foo<A>在给定的编译单元中;第二个是对第一个实例化点的引用。

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

有些编译器甚至会记住从一个编译单元到另一个编译单元的模板实例化;Foo<A>将有一个::value那是false即使foo2已创建(具有完整的A)。其他人会有两种不同的Foo<A>每个编译单元中的 s;它的方法将被标记为内联(并且是不同的),类的大小可能不一致,并且您将遇到一连串不良的程序问题。


最后,请注意,许多类型std要求它们的模板参数在旧版本的 C++ 中是完整的(包括c++11 /questions/tagged/c%2b%2b11:“17.6.4.8 其他函数 (...) 2. 在以下情况下效果未定义:(...) 特别是 - 如果在实例化模板组件时使用不完整类型 (3.9) 作为模板参数,除非特别允许该组件”——复制自 boost 不完整容器文档)。具体来说,std::vector<T>曾经要求T是完整的。

By c++17 /questions/tagged/c%2b%2b17具有改变为std::vector https://stackoverflow.com/a/44675477/1774667:

[向量.概述]/3

如果分配器满足分配器完整性要求 17.6.3.5.1,则在实例化向量时可以使用不完整类型 T。 T 应在引用所得向量专业化的任何成员之前完成。

现在,甚至在此之前c++17 /questions/tagged/c%2b%2b17,大多数实现std::vector<T>不完整也可以T直到您尝试使用一个方法(包括它的许多构造函数或析构函数),但标准规定T must是完整的。

This actually gets in the way of some unuseful code, like having a function type that returns vectors of its own type1. Boost https://www.boost.org/doc/libs/1_48_0/doc/html/container/containers_of_incomplete_types.html has a library to solve this problem.


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

的身体Foo<T>::Foo()仅在“被调用时”实例化。所以T未完成不会产生任何影响,直到Foo::Foo()叫做。

Foo<A> foo;

^^ 将无法以不完整的方式编译A.

using foo_t = Foo<A>;

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

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

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


1 Can you say state machine transition function?

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如果类型是事后定义的,则实例化具有不完整类型的类模板是否格式错误? 的相关文章

  • Signalr 在生产服务器中总是陷入长轮询

    当我在服务器中托管应用程序时 它会检查服务器端事件并始终回退到长轮询 服务器托管环境为Windows Server 2012 R1和IIS 7 5 无论如何 我们是否可以解决这个问题 https cloud githubuserconten
  • 在 Xamarin Android 中将图像从 URL 异步加载到 ImageView 中

    我有一个包含多个项目的 ListView 列表中的每个项目都应该有一个与之关联的图像 我创建了一个数组适配器来保存每个列表项并具有我希望加载的图像的 url 我正在尝试使用 Web 请求异步加载图像 并设置图像并在加载后在视图中更新它 但视
  • fgets() 和 Ctrl+D,三次才能结束?

    I don t understand why I need press Ctrl D for three times to send the EOF In addition if I press Enter then it only too
  • Cygwin 下使用 CMake 编译库

    我一直在尝试使用 CMake 来编译 TinyXML 作为一种迷你项目 尝试学习 CMake 作为补充 我试图将其编译成动态库并自行安装 以便它可以工作 到目前为止 我已经设法编译和安装它 但它编译成 dll 和 dll a 让它工作的唯一
  • 使用 Microsoft Graph API 订阅 Outlook 推送通知时出现 400 错误请求错误

    我正在尝试使用 Microsoft Graph API 创建订阅以通过推送通知获取 Outlook 电子邮件 mentions 我在用本文档 https learn microsoft com en us graph api subscri
  • 将字符串从非托管代码传递到托管

    我在将字符串从非托管代码传递到托管代码时遇到问题 在我的非托管类中 非托管类 cpp 我有一个来自托管代码的函数指针 TESTCALLBACK FUNCTION testCbFunc TESTCALLBACK FUNCTION 接受一个字符
  • 使用 C# 在 WinRT 中获取可用磁盘空间

    DllImport kernel32 dll SetLastError true static extern bool GetDiskFreeSpaceEx string lpDirectoryName out ulong lpFreeBy
  • 如何针对 Nancy 中的 Active Directory 进行身份验证?

    这是一篇过时的文章 但是http msdn microsoft com en us library ff650308 aspx paght000026 step3 http msdn microsoft com en us library
  • C# 用数组封送结构体

    假设我有一个类似于 public struct MyStruct public float a 我想用一些自定义数组大小实例化一个这样的结构 在本例中假设为 2 然后我将其封送到字节数组中 MyStruct s new MyStruct s
  • 按字典顺序对整数数组进行排序 C++

    我想按字典顺序对一个大整数数组 例如 100 万个元素 进行排序 Example input 100 21 22 99 1 927 sorted 1 100 21 22 927 99 我用最简单的方法做到了 将所有数字转换为字符串 非常昂贵
  • A* 之间的差异 pA = 新 A;和 A* pA = 新 A();

    在 C 中 以下两个动态对象创建之间的确切区别是什么 A pA new A A pA new A 我做了一些测试 但似乎在这两种情况下 都调用了默认构造函数 并且仅调用了它 我正在寻找性能方面的任何差异 Thanks If A是 POD 类
  • 使用向量的 merge_sort 在少于 9 个输入的情况下效果很好

    不知何故 我使用向量实现了合并排序 问题是 它可以在少于 9 个输入的情况下正常工作 但在有 9 个或更多输入的情况下 它会执行一些我不明白的操作 如下所示 Input 5 4 3 2 1 6 5 4 3 2 1 9 8 7 6 5 4 3
  • C 中的位移位

    如果与有符号整数对应的位模式右移 则 1 vacant bit will be filled by the sign bit 2 vacant bit will be filled by 0 3 The outcome is impleme
  • 将应用程序从 Microsoft Access 迁移到 VB 或 C#.NET

    我目前正试图说服管理层需要将我们的应用程序之一移植到 NET 该应用程序已经发展成为 Access 中的一个庞然大物 SQL 后端 拥有 700 个链接表 650 个表单 子表单 130 个模块和 850 个查询 我几乎知道这样做的所有主要
  • 已过时 - OpenCV 的错误模式

    我正在使用 OpenCV 1 进行一些图像处理 并且对 cvSetErrMode 函数 它是 CxCore 的一部分 感到困惑 OpenCV 具有三种错误模式 叶 调用错误处理程序后 程序终止 Parent 程序没有终止 但错误处理程序被调
  • 在Linux中使用C/C++获取机器序列号和CPU ID

    在Linux系统中如何获取机器序列号和CPU ID 示例代码受到高度赞赏 Here http lxr linux no linux v2 6 39 arch x86 include asm processor h L173Linux 内核似
  • 方法参数内的变量赋值

    我刚刚发现 通过发现错误 你可以这样做 string s 3 int i int TryParse s hello out i returns false 使用赋值的返回值是否合法 Obviously i is but is this th
  • 在 ASP.NET 中将事件冒泡为父级

    我已经说过 ASP NET 中的层次结构 page user control 1 user control 2 control 3 我想要做的是 当控件 3 它可以是任何类型的控件 我一般都想这样做 让用户用它做一些触发回发的事情时 它会向
  • C++ 成员函数中的“if (!this)”有多糟糕?

    如果我遇到旧代码if this return 在应用程序中 这种风险有多严重 它是一个危险的定时炸弹 需要立即在应用程序范围内进行搜索和销毁工作 还是更像是一种可以悄悄留在原处的代码气味 我不打算writing当然 执行此操作的代码 相反
  • 将 viewbag 从操作控制器传递到部分视图

    我有一个带有部分视图的 mvc 视图 控制器中有一个 ActionResult 方法 它将返回 PartialView 因此 我需要将 ViewBag 数据从 ActionResult 方法传递到 Partial View 这是我的控制器

随机推荐