C++20 Concepts:结构体首成员地址检查约束异常问题咨询
问题解析
1. 为什么你的代码能正常编译?
你误解了C++ concept中requires表达式的作用——它不要求表达式在编译期求值,只要求表达式本身是语法合法、类型匹配的有效代码。
你的约束里的指针比较static_cast<void*>(&s) == static_cast<void*>(&s.next),本质上只是在检查两件事:
- 类型
T确实包含名为next的成员 - 对
T的实例s取地址、对s.next取地址,再转成void*的操作是合法的
只要这两个条件满足,requires表达式就会判定为“符合要求”,完全不会去计算这个比较表达式的运行时结果,所以哪怕指针比较的结果是false,约束依然会通过。这就是为什么你觉得指针不是编译时常量,但代码还能编译的原因——concept根本没要求它是编译期常量。
2. 为什么约束会错误判定结构体?
因为你的约束逻辑完全偏离了需求:你想检查next是结构体的首个成员,但当前的约束只检查了T有next成员,完全没涉及成员的位置判断。
对于你的测试结构体mystruct,它确实有next成员,所以requires表达式里的所有操作都是合法的,约束自然会判定它符合要求,哪怕next是第三个成员。
3. 正确的实现方式
要在编译期检查某个成员是标准布局结构体的首个成员,可以利用offsetof宏(对于标准布局类型,offsetof是编译期常量),结合constexpr表达式来实现:
#include <cstddef> #include <type_traits> template<typename T> concept has_first_member_next = std::is_standard_layout_v<T> && requires { offsetof(T, next); } && // 检查存在next成员 (offsetof(T, next) == 0);
这样一来:
std::is_standard_layout_v<T>确保类型是标准布局,保证offsetof的行为符合预期requires { offsetof(T, next); }检查T确实有next成员offsetof(T, next) == 0直接在编译期判断next是否是首个成员(偏移量为0)
用你的测试结构体mystruct测试时,offsetof(mystruct, next)的值是8(假设int为4字节),不等于0,所以约束会正确判定它不符合要求。
内容的提问来源于stack exchange,提问作者Daniel
相关产品推荐
相关产品推荐

