C++20 Concepts定义成员类型约束时编译失败问题咨询
C++20 Concepts检测类成员类型问题
我在入门C++20 Concepts时遇到一个问题:想要定义一个Concept,要求类必须包含名为count_、类型为int的成员。
编写的Concept代码
#include <concepts> template <typename T> concept HasCount = requires(T thing) { { thing.count_ } -> std::same_as<int>; };
目标结构体
这个结构体应该满足上述Concept:
struct BaseTableChunk { BaseTableChunk* next_; int count_ = 0; int data_[1000]; };
使用Concept的代码
但后续使用该Concept的代码无法通过编译:
template <HasCount Chunk> class BaseTable { void doSomething(); }; int main() { BaseTable<BaseTableChunk> table{}; return 0; }
编译器报错信息
note: constraints not satisfied In file included from /usr/include/c++/10/compare:39, from /usr/include/c++/10/bits/stl_pair.h:65, from /usr/include/c++/10/bits/stl_algobase.h:64, from /usr/include/c++/10/bits/char_traits.h:39, from /usr/include/c++/10/ios:40, from /usr/include/c++/10/ostream:38, from /usr/include/c++/10/iostream:39, from Minimal2.cxx:1: /usr/include/c++/10/concepts:57:15: required for the satisfaction of ‘__same_as<_Tp, _Up>’ [with _Tp = int&; _Up = int] /usr/include/c++/10/concepts:62:13: required for the satisfaction of ‘same_as<int&, int>’ /usr/include/c++/10/concepts:57:32: note: the expression ‘is_same_v<_Tp, _Up> [with _Tp = int&; _Up = int]’ evaluated to ‘false’ 57 | concept __same_as = std::is_same_v<_Tp, _Up>;
问题分析与疑问
我发现thing.count_被解析为返回int&而非int,导致约束不满足。虽然改成{ thing.count_ } -> std::same_as<int&>可以编译,但这种写法很违反直觉——我想检测的是成员本身的类型是int,而不是表达式的引用类型。
解决方案
有两种更符合直觉的写法可以解决这个问题:
方案1:使用std::convertible_to<int>
如果只要求成员类型可以隐式转换为int(对于int成员来说完全满足),可以用std::convertible_to代替std::same_as,它会忽略引用的影响:
template <typename T> concept HasCount = requires(T thing) { { thing.count_ } -> std::convertible_to<int>; };
方案2:直接检测成员的底层类型
如果需要严格检测成员本身的类型是int,可以结合std::remove_reference_t和decltype来剥离引用:
#include <concepts> #include <type_traits> template <typename T> concept HasCount = requires(T thing) { requires std::same_as<std::remove_reference_t<decltype(thing.count_)>, int>; };
或者更直接地检查类的成员类型(注意:如果count_是私有成员,这种写法会因无法访问而失败,而requires表达式通过对象访问的方式可以访问私有成员):
template <typename T> concept HasCount = std::same_as<decltype(T::count_), int>;
原因解释
当你通过对象访问非静态数据成员时,表达式的类型是左值引用(比如int&),因为这个表达式是可修改的左值。原来的std::same_as<int>会严格匹配类型,包括引用修饰符,所以不通过。而上面的方案要么放宽了匹配条件,要么直接获取了成员的原始类型。
内容的提问来源于stack exchange,提问作者E_3
相关产品推荐
相关产品推荐

