如何在C++中约束函数对象仅接受任意类型的单个引用参数?
问题描述
我正在探索C++的进阶特性,实现了一个可遍历tuple每个元素并执行传入函数的模板。由于tuple的元素类型多样,我希望约束传入的函数对象仅能接受任意类型的单个引用参数,但尝试使用std::invocable<auto&>并未成功。相关代码如下:
#include <concepts> #include <tuple> #include <utility> /* index_sequence */ template <class Tuple, std::invocable<auto&> F> inline constexpr decltype(auto) for_each_in_tuple(Tuple&& tuple, F&& f) { return [] <std::size_t... I> (Tuple&& tuple, F&& f, std::index_sequence<I...>) { (f(std::get<I>(tuple)), ...); return f; }(std::forward<Tuple>(tuple), std::forward<F>(f), std::make_index_sequence<std::tuple_size<std::remove_reference_t<Tuple>>::value>{}); }
请问有可行的解决思路吗?
解决思路
1. 明确std::invocable<auto&>的问题
std::invocable<auto&>不符合C++标准概念的语法规则,auto在这里无法被推导为"任意类型",编译器无法识别这种写法。需要自定义概念来实现预期约束。
2. 自定义"接受任意单个引用"的概念
可以编写一个概念,检查函数对象是否能接受任意类型的左值引用:
template <typename F> concept accepts_any_single_reference = requires(F f, auto& arg) { f(arg); };
如果需要同时支持右值引用,可调整为:
template <typename F> concept accepts_any_single_reference = requires(F f, auto&& arg) { f(std::forward<decltype(arg)>(arg)); };
3. 替换模板中的约束
将原模板的std::invocable<auto&>替换为自定义概念,修改后的完整代码:
#include <concepts> #include <tuple> #include <utility> template <typename F> concept accepts_any_single_reference = requires(F f, auto& arg) { f(arg); }; template <class Tuple, accepts_any_single_reference F> inline constexpr decltype(auto) for_each_in_tuple(Tuple&& tuple, F&& f) { return [] <std::size_t... I> (Tuple&& tuple, F&& f, std::index_sequence<I...>) { (f(std::get<I>(tuple)), ...); return std::forward<F>(f); }(std::forward<Tuple>(tuple), std::forward<F>(f), std::make_index_sequence<std::tuple_size<std::remove_reference_t<Tuple>>::value>{}); }
4. 进阶优化:针对当前tuple元素的精准约束
如果只需要函数能处理当前tuple的所有元素(而非任意类型),可以定义更贴合场景的概念:
template <class Tuple, typename F> concept invocable_for_all_tuple_elements = []<std::size_t... I>(std::index_sequence<I...>) { return (std::invocable<F&, decltype(std::get<I>(std::declval<Tuple>()))> && ...); }(std::make_index_sequence<std::tuple_size_v<std::remove_reference_t<Tuple>>>{});
这个概念会逐一检查函数是否能被tuple的每一个元素调用,避免过度约束。
内容的提问来源于stack exchange,提问作者glades
相关产品推荐
相关产品推荐

