std::ranges是否提供谓词适配器/构建器?相关使用疑问
关于C++ Ranges与Views的谓词复用问题
我正在试验ranges和views的组合,但找不到表达常见谓词模式的方法。
我有一个键值对容器:
std::vector<std::pair<int, std::string>> countries = { { 1, "Germany"}, { 2, "UK"}, { 3, "Spain"}, { 4, "Sweden"} };
我想要找到键为3的第一个元素并复制其值,当前实现如下:
std::vector<std::string> result; int key = 3; std::ranges::copy( (countries | std::views::filter([key](auto const &p){ return p.first == key; }) | std::views::take(1) | std::views::values ), std::back_inserter(result));
我经常需要重复编写像“key_equals_to”、“value_not_equals_to”这类简单谓词,显得冗余。
问题1
是否可以通过标准库组合/表达这类简单谓词,无需重复编写此类lambda?或者我应该自行编写一套通用谓词库?有没有优秀的此类库示例?
问题2
我原本想使用适配器std::views::keys来获取pair::first,但这样会让后续管道无法访问pair::second。有没有其他基于ranges/views的方法实现此需求?
问题1的解答
标准库本身没有直接提供开箱即用的这类谓词适配器,但可以通过组合现有工具实现复用:
- 利用
std::equal_to配合投影参数:std::ranges::filter支持第三个投影参数,可将元素映射到需要比较的字段,结合std::bind_front绑定目标值,写法如下:
这里std::views::filter(std::bind_front(std::equal_to<int>(), key), &std::pair<int, std::string>::first)&std::pair<int, std::string>::first是投影函数,把pair映射到first成员,std::bind_front将key绑定到equal_to的第一个参数,实现键匹配逻辑。 - 若觉得上述写法仍繁琐,可自行封装轻量级通用谓词:
后续使用时直接写template<typename Key> auto key_equals_to(Key&& key) { return [key = std::forward<Key>(key)](auto const& pair) { return pair.first == key; }; } template<typename Value> auto value_not_equals_to(Value&& val) { return [val = std::forward<Value>(val)](auto const& pair) { return pair.second != val; }; }std::views::filter(key_equals_to(3))即可,简洁直观。
现成库方面,Boost.Range提供了丰富的谓词适配器工具,比如支持投影的boost::range::equal_to,但如果不想引入第三方依赖,自己封装轻量工具是更简单的选择。
问题2的解答
std::views::keys会将pair转换为first成员,确实会丢失对second的访问权。要基于键筛选且保留原pair的完整访问,有两种可行思路:
- 直接在
filter中使用lambda或自定义谓词(即你当前的写法),这样整个pair会在管道中完整传递,后续可通过std::views::values提取需要的字段。 - 如果想显式处理键再关联原pair,可尝试
std::views::enumerate或自定义适配器,但这会增加代码复杂度,远不如直接在filter中做键判断高效。
另外,如果你只是要获取第一个匹配键的值,完全可以不用视图管道,改用std::ranges::find_if配合投影更简洁:
auto it = std::ranges::find_if(countries, std::bind_front(std::equal_to<int>(), 3), &std::pair<int, std::string>::first); if (it != countries.end()) { std::vector<std::string> result{it->second}; }
内容的提问来源于stack exchange,提问作者Grim Fandango
相关产品推荐
相关产品推荐

