如何在C++概念中为成员函数参数应用概念并使用?
C++概念中为成员函数参数应用概念的变通方案
这是某问题的后续场景,其中单参数的约束需求尚未解决。现有如下C++概念定义:
template <typename T> concept has_set = requires(T t, std::string s) { { t.set(s) } -> std::same_as<void>; };
我们希望为set函数的参数s添加概念约束(比如要求该参数类型可转换为std::string_view),但直接在requires表达式的参数列表中使用std::convertible_to<std::string_view>会导致编译失败,例如以下写法无法通过编译:
template <typename T> concept has_set = requires(T t, std::convertible_to<std::string_view> s) { { t.set(s) } -> std::same_as<void>; };
需要找到可行的变通方法,让以下代码能够正常编译:
std::string use(has_set auto & f) { /* ... 使用 f.set(...) ... */ }
可行的变通方案
方案1:利用模板化的requires表达式验证
通过在requires表达式中引入模板参数并添加约束,来验证set函数是否能接受所有满足std::convertible_to<std::string_view>的类型:
template <typename T> concept has_set = requires(T t) { template <std::convertible_to<std::string_view> S> { t.set(std::declval<S>()) } -> std::same_as<void>; };
该写法依赖C++20及以上标准,需确保编译器开启对应标准支持。
方案2:用满足约束的具体类型替代概念参数
由于只要set函数能接受std::string_view,所有可转换为它的类型(如std::string、const char*等)都能通过隐式转换传入,因此可以直接用std::string_view作为requires表达式中的测试参数:
template <typename T> concept has_set = requires(T t, std::string_view s) { { t.set(s) } -> std::same_as<void>; };
这种写法简洁高效,兼容性好,是最常用的解决方案。
方案3:嵌套requires表达式做精确验证
如果需要更细致的类型检查,可以通过嵌套requires表达式,先获取参数类型再验证约束:
template <typename T> concept has_set = requires { requires std::same_as<decltype(std::declval<T>().set(std::declval<std::string_view>())), void>; };
此写法能精确验证set函数接受std::string_view时的返回值为void,但相对繁琐,仅在特殊场景下需要使用。
内容的提问来源于stack exchange,提问作者Markus W.
相关产品推荐
相关产品推荐

