如何约束模板函数以适配模板类型的任意范围?
约束泛型函数接受元素为
result_t<T>的任意范围 问题背景
先定义了以下模板类型及别名:
template<typename T> struct result_t { T value; }; template<typename elem_type> using list_t = std::vector<result_t<elem_type>>;
原本有一个仅接受std::vector<result_t<elem_type>>的硬编码函数:
template<typename elem_type> auto values(const std::vector<result_t<elem_type>>& values) {...}
现在需要将该函数改为泛型,支持任意符合标准的范围(包括view),尝试定义is_result_range concept时编译器报错无法推导模板参数,错误的concept实现如下:
template<typename range_t, typename element_t> concept is_result_range = std::ranges::range<range_t> && std::is_same_v<typename std::ranges::range_value_t<range_t>, result<element_t>>;
错误原因
上述concept包含两个模板参数range_t和element_t,但使用template<is_result_range range_t>时仅传入了range_t,编译器无法自动推导element_t,导致报错。
解决方案
需要将concept改为仅接受一个模板参数range_t,并检查范围的元素类型是否为result_t<U>(U为任意类型),以下是两种可行实现:
方法1:使用辅助类型特征
先定义判断类型是否为result_t<U>的类型特征,再基于此实现concept:
// 辅助类型特征:判断T是否是result_t<U>的实例 template<typename T> struct is_result_t : std::false_type {}; template<typename U> struct is_result_t<result_t<U>> : std::true_type {}; template<typename T> constexpr bool is_result_t_v = is_result_t<T>::value; // 最终的concept定义 template<typename range_t> concept is_result_range = std::ranges::range<range_t> && is_result_t_v<std::ranges::range_value_t<range_t>>;
方法2:直接在concept中使用模板推导(C++20+)
利用C++20的模板参数推导能力,在concept的requires子句中直接匹配元素类型:
template<typename range_t> concept is_result_range = std::ranges::range<range_t> && requires { // 尝试将范围的首元素绑定到result_t<U>的引用,推导U []<typename U>(const result_t<U>&) {}(*std::ranges::begin(std::declval<range_t>())); };
完整使用示例
#include <vector> #include <ranges> #include <iostream> #include <type_traits> template<typename T> struct result_t { T value; }; template<typename elem_type> using list_t = std::vector<result_t<elem_type>>; // 方法1的辅助类型特征 template<typename T> struct is_result_t : std::false_type {}; template<typename U> struct is_result_t<result_t<U>> : std::true_type {}; template<typename T> constexpr bool is_result_t_v = is_result_t<T>::value; template<typename range_t> concept is_result_range = std::ranges::range<range_t> && is_result_t_v<std::ranges::range_value_t<range_t>>; // 泛型values函数 template<is_result_range range_t> auto values(const range_t& values) { // 推导元素的实际类型U using elem_type = std::remove_cvref_t<decltype(std::ranges::range_value_t<range_t>::value)>; std::vector<elem_type> result; for (const auto& item : values) { result.push_back(item.value); } return result; } int main() { // 测试vector list_t<int> int_list = {{1}, {2}, {3}, {4}}; auto int_values = values(int_list); for (int v : int_values) { std::cout << v << " "; } std::cout << "\n"; // 测试view auto odd_view = int_list | std::views::filter([](const auto& r) { return r.value % 2 != 0; }); auto odd_values = values(odd_view); for (int v : odd_values) { std::cout << v << " "; } return 0; }
内容的提问来源于stack exchange,提问作者CJCombrink
相关产品推荐
相关产品推荐

