为什么C++20的要求表达式的行为不符合预期?
#include <type_traits>
template<typename T>
struct IsComplete final
: std::bool_constant<requires{sizeof(T);}>
{};
int main()
{
struct A;
static_assert(!IsComplete<A>::value); // ok
struct A{};
static_assert(IsComplete<A>::value); // error
}
我预计第二个static_assert应该是真的,因为 A 现在是一个完整的类型。
为什么 C++20 的要求表达式的行为不符合预期?
回答
这是一个错误的期望。首先,类模板在翻译单元中只有一个实例化点:
[温度点]
7 ... 类模板的特化在翻译单元中至多有一个实例化点。任何模板的特化都可能在多个翻译单元中具有实例化点。如果根据一个定义规则,两个不同的实例化点赋予模板特化不同的含义,则程序格式错误,无需诊断。
模板从不允许程序中的两个点对同一组参数的模板有不同的解释(一般情况下是 ODR 的噩梦)。你基本上开始冒险进入鼻恶魔领域,因为你尝试了这个特性。
如果您认为使用 C++20 概念会改变任何事情,您将直接陷入格式错误;如果您将示例概念化,则无需诊断领域
template<typename T>
concept IsComplete = requires{sizeof(T);};
int main()
{
struct A;
static_assert(!IsComplete<A>); // ok
struct A{};
static_assert(IsComplete<A>); // error or nuclear launch.
}
[临时名称]
8 ... 如果指定的模板参数满足概念的规范化约束表达式 ([temp.constr.constr]),则概念 id 评估为真,否则为假。
[temp.constr.atomic]
3 ...如果在程序的不同点,对于相同的原子约束和模板参数,满意结果不同,则程序格式错误,不需要诊断。
这不是什么新东西,概念只是增加了更多相同的东西。如果参数的某些属性在程序中的两个不同点不同,则模板对于特定参数集的含义不得更改。
所以,当一个概念(即使是在预先C ++ 20 SFINAE两轮牛车)来检查,如果一个类型是完全可以被写入,不慎使用它是玩火。
- In this case, @md2perpe, that's because each `struct A` defines a distinct type, and thus `IsComplete` will be [instantiated twice](https://godbolt.org/z/KjrcPPdde).