如何检查 C++ 类是不是不完整(仅声明)?

Posted

技术标签:

【中文标题】如何检查 C++ 类是不是不完整(仅声明)?【英文标题】:How to check that a C++ class is incomplete (only declared)?如何检查 C++ 类是否不完整(仅声明)? 【发布时间】:2021-10-04 23:34:37 【问题描述】:

我想写一个 C++ 函数来检查它的模板参数类是不完整的,所以只有类声明可用,而不是所有类成员的完整定义。

我的函数incomplete()加上一些演示程序如下所示:

#include <type_traits>
#include <iostream>

template <typename T, typename V = void> constexpr bool is_incomplete = true;
template <typename T> constexpr bool is_incomplete<T, std::enable_if_t<sizeof(T)>> = false;
template <typename T> constexpr bool incomplete()  return is_incomplete<T>; 

struct A;
void print()  std::cout << incomplete<A>(); 
struct A ; //this line affects GCC

int main()

    print();

它在 Clang 打印 1 中运行良好,但在 GCC 中程序打印 0,尽管事实上 A 类在函数 print 中不完整。 https://gcc.godbolt.org/z/qWW3hqbEv

这里是 GCC 错误还是我的程序有问题?

【问题讨论】:

is_complete/is_incomplete 很容易出现 ODR 违规/不一致的结果。 EOF 是一个有效的实例化点。对于函数,每个实例化的定义应该相同,对于类,它只实例化一次。不确定模板变量。 相关/欺骗***.com/questions/1625105/… 但我认为那里的大多数答案都存在与您相同/相似的问题 这可能是唯一正确的:***.com/a/21119631/4117728 【参考方案1】:

目前尚未确定哪个编译器是正确的。我是CWG Issue 1845。

13.8.4.1 [temp.point] 的当前措辞没有定义变量模板特化的实例化点。大概在第 1 段和第 8 段中用“变量模板”替换对“类模板的静态数据成员”的引用就足够了。

鉴于该问题仍处于起草阶段(尚无规范性措辞,但它是最新的可用草案),它仍未得到解决。目前尚不清楚变量模板是否可以具有多个实例化点(尽管问题报告者建议的方向很明确)。

对于具有多个实例化点的实体,翻译单元的结尾也是一个。此外,如果两点在模板的定义上存在分歧,那就是违反了 ODR,简单明了。 GCC 似乎提供了两点,所以你会看到结果。我倾向于同意 GCC 的观点。变量模板在很多方面是类模板的静态数据成员的简写,而静态数据成员确实有多个实例化点。

不管怎样,这都是在冒着鼻恶魔的风险。如果该状态可以在 TU 中更改(并且可能即使它可以在整个程序中更改),那么检查类型的完整性实际上是不可能的。

【讨论】:

【参考方案2】:

看起来如果某个类在某个时候变得完整,则发现一个类是否不完整将违反一个定义规则 (ODR),因此该问题应该没有有效的解决方案。

我被建议的来自https://eel.is/c++draft/temp.point 的更多引用:

1 对于函数模板特化...实例化点...紧跟在引用特化的命名空间范围声明或定义之后。

7 函数模板的特化 ... 在翻译单元内可能有多个实例化点,除了上述实例化点之外,

对于在...翻译单元...内具有实例化点的任何此类特化,... [end of] 翻译单元之后的点也被视为实例化点,

如果两个不同的实例化点根据单一定义规则赋予模板特化不同的含义,则程序是非良构的,不需要诊断。

【讨论】:

适用于模板函数。对于类,只有一个实例化... :-/

以上是关于如何检查 C++ 类是不是不完整(仅声明)?的主要内容,如果未能解决你的问题,请参考以下文章

无法弄清楚如何通过仅使用类的函数删除整个链接列表

如何使我的 C++ 类事件系统成为仅限于类型数组的模板类?

如何在C++中获得完整的类型名称

C++ 中的模板类声明头文件和实现文件分离后,如何能实现正常编译?

如何使用 Qt (C++) 检查程序是不是按其名称运行

如何使用正则表达式检查用户输入是不是仅包含特殊字符?