问题描述
我想编写一个 C++ 函数来检查其模板参数类是否不完整,因此只有类声明可用,但没有包含所有类成员的完整定义。
我的函数 {
"name": "landing-page","version": "0.1.0","private": true,"dependencies": {
"@testing-library/jest-dom": "^5.14.1","@testing-library/react": "^11.2.7","@testing-library/user-event": "^12.8.3","bootstrap": "^5.0.2","husky": "^7.0.1","lint-staged": "^11.1.1","prettier": "^2.3.2","react": "^17.0.2","react-bootstrap": "^2.0.0-beta.4","react-dom": "^17.0.2","react-router-dom": "^5.2.0","react-scripts": "4.0.3","styled-components": "^5.3.0","web-vitals": "^1.1.2"
},"lint-staged": {
"src/**/*.{js,jsx,ts,tsx,json,css,scss,md}": [
"prettier --write"
]
},"scripts": {
"start": "react-scripts start","build": "react-scripts build","test": "react-scripts test","eject": "react-scripts eject"
},"eslintConfig": {
"extends": [
"react-app","react-app/jest"
]
},"browserslist": {
"production": [
">0.2%","not dead","not op_mini all"
],"development": [
"last 1 chrome version","last 1 firefox version","last 1 safari version"
]
},"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},"devDependencies": {
"@babel/core": "^7.14.8"
}
}
与一些演示程序一起看起来如下:
incomplete()
它在 Clang 打印 #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();
}
中运行良好,但在 GCC 中,尽管 1
类在函数 0
中不完整,但程序打印 A
。
https://gcc.godbolt.org/z/qWW3hqbEv
这里是 GCC 错误还是我的程序有问题?
解决方法
哪个编译器是正确的目前还没有决定。是 CWG Issue 1845。
13.8.4.1 [temp.point] 的当前措辞没有定义变量模板特化的实例化点。据推测,将第 1 段和第 8 段中对“类模板的静态数据成员”的引用替换为“变量模板”就足够了。
鉴于该问题仍处于起草阶段(并且尚无规范性措辞,但它是最新的可用草案),它仍未解决。尚不清楚变量模板是否可以有多个实例化点(尽管问题报告者建议的方向很明确)。
对于具有多个实例化点的实体,翻译单元的结尾也是一个。此外,如果有两点对模板的定义不一致,那就是 ODR 违规,简单明了。 GCC 似乎提供了两点,所以你会看到结果。我倾向于在这里同意 GCC。变量模板在很多方面都是类模板的静态数据成员的简写,并且静态数据成员确实有多个实例化点。
不管怎样,这都是在冒鼻鬼的风险。如果状态可以在 TU 中改变(甚至可能在整个程序中改变),那么检查类型的完整性就不太可能可靠。
,看起来,如果某个类在某个时候变得完整,那么判断一个类是否不完整将违反一个定义规则 (ODR),因此该问题应该没有有效的解决方案。
我被推荐的来自 https://eel.is/c++draft/temp.point 的更多引用:
1 对于函数模板特化 ... 实例化点 ... 紧跟在引用该特化的命名空间范围声明或定义之后。
7 一个函数模板的特化......在一个翻译单元内可能有多个实例化点,并且除了上面描述的实例化点,
对于任何在 ... 翻译单元 ... 内具有实例化点的特化,翻译单元 ... [结束] 之后的点也被视为实例化点,
如果两个不同的实例化点根据一个定义规则赋予模板特化不同的含义,则程序格式错误,无需诊断。