如何在C++概念中为成员函数参数应用概念约束?
为C++概念中的函数参数应用概念约束的解决方案
先看原始的has_set概念,它要求类型T拥有一个接受std::string参数、返回void的set成员函数:
template <typename T> concept has_set = requires(T t, std::string s) { { t.set(s) } -> std::same_as<void>; };
如果尝试直接给参数s应用std::convertible_to<std::string_view>约束,像下面这样写会编译失败——因为C++标准不允许在requires子句的参数声明里直接用concept作为类型:
template <typename T> concept has_set = requires(T t, std::convertible_to<std::string_view> s) { { t.set(s) } -> std::same_as<void>; };
下面是几种可行的解决技巧:
方法1:新增带约束的模板参数
给概念额外添加一个模板参数S,先对S应用std::convertible_to<std::string_view>约束,再在requires子句中使用这个类型:
template <typename T, typename S> concept has_set_for = std::convertible_to<S, std::string_view> && requires(T t, S s) { { t.set(s) } -> std::same_as<void>; };
使用时需要显式指定S的类型,比如has_set_for<MyType, std::string>。
方法2:用auto配合约束声明参数
C++20及以后支持在requires子句的参数中用auto加concept约束,这种写法不需要额外模板参数,更简洁:
template <typename T> concept has_set = requires(T t, std::convertible_to<std::string_view> auto s) { { t.set(s) } -> std::same_as<void>; };
编译器会自动推导并检查s的类型是否满足std::convertible_to<std::string_view>,同时验证t.set(s)的返回值是否为void。
针对后续需求:无需显式指定模板参数使用概念
如果希望使用概念时不用显式指定额外模板参数,确保任意可转换为std::string_view的类型都能被T的set函数接受,可以用嵌套的requires表达式:
template <typename T> concept has_set = requires { requires std::convertible_to<std::string_view> auto s; requires requires(T t, decltype(s) s_val) { { t.set(s_val) } -> std::same_as<void>; }; };
或者用std::invocable简化(适用于set是可访问的成员函数且签名明确的场景):
template <typename T> concept has_set = std::invocable<decltype(&T::set), T, std::convertible_to<std::string_view>>;
内容的提问来源于stack exchange,提问作者Markus W.
相关产品推荐
相关产品推荐

