C++ concept如何要求匹配的形参必须为&引用类型
问题根因
原有Consumer约束失效的核心逻辑是:requires块中的调用校验仅检查「传入Source&类型实参时,调用表达式是否合法、返回值是否匹配」。当被校验的operator()按值接收Source类型参数时,传入左值引用会触发拷贝构造,调用本身完全合法,因此会错误通过约束校验。
原有约束没有直接校验operator()形参的精确类型,自然无法拦截值传递的写法。
修正方案
需要在原有可调用性、返回值校验的基础上,新增对operator()第一个形参精确类型的校验,强制要求其必须为Source&左值引用类型。
可以通过成员函数指针提取形参类型的方式实现精确校验,修正后的完整代码如下:
#include <string> #include <ranges> #include <type_traits> // 辅助萃取器:提取成员函数的第一个形参类型 template <class Fn> struct first_param_type; // 匹配非const成员函数 template <class Ret, class Class, class FirstArg, class... RestArgs> struct first_param_type<Ret(Class::*)(FirstArg, RestArgs...)> { using type = FirstArg; }; // 匹配const成员函数 template <class Ret, class Class, class FirstArg, class... RestArgs> struct first_param_type<Ret(Class::*)(FirstArg, RestArgs...) const> { using type = FirstArg; }; template <class Type, class Source> concept Consumer = requires(Type type, Source& source, std::ranges::iterator_t<Source> position) { // 保留原有可调用性、返回值校验 { type(source, position) } -> std::same_as<Source>; // 新增精确类型约束:第一个形参必须是Source& requires std::same_as< typename first_param_type<decltype(&Type::operator())>::type, Source& >; }; struct String { public: // 该写法第一个参数是值传递,现在会被约束拦截 std::string operator()(const std::string source, std::string::const_iterator position) { return "test"; } }; // 合法的Consumer实现示例 struct ValidConsumer { public: std::string operator()(std::string& source, std::string::const_iterator position) { return source; } }; int main() { String consumer{}; // 下面的静态断言现在会编译失败,符合预期 // static_assert(Consumer<String, std::string>); ValidConsumer valid_consumer{}; // 合法实现可以正常通过约束 static_assert(Consumer<ValidConsumer, std::string>); auto test = std::string("test"); valid_consumer(test, std::begin(test)); return 0; }
效果说明
- 原有值传递的
String::operator()会被正确拦截,static_assert触发编译失败 - 第一个形参为
const Source&、Source&&、值传递的写法都无法通过约束 - 只有第一个形参精确为
Source&左值引用的实现才能满足Consumer要求
内容的提问来源于stack exchange,提问作者Robbie
相关产品推荐
相关产品推荐

