如何在C++20标准库Ranges操作中直接使用成员函数
解决C++20 Ranges中使用成员函数/变量作为过滤、转换谓词的问题
你的核心问题在于两个关键点:
fs::directory_entry::is_regular_file存在重载,直接取成员函数指针会导致歧义- 成员函数指针不能直接作为
std::views::filter的谓词,需要适配成可直接调用的对象(成员变量指针同理需要适配,不过C++20的transform对成员变量指针支持更友好)
错误原因拆解
- 第一次尝试直接写
fs::directory_entry::is_regular_file:编译器认为你试图调用函数但缺少括号,因此提示需要用&获取成员函数指针。 - 第二次尝试
&fs::directory_entry::is_regular_file:该函数有两个重载(带/不带std::error_code参数),编译器无法确定你要引用哪个版本;同时成员函数指针无法直接被filter调用(它需要绑定到对象实例才能执行),因此出现匹配错误。 - 第三次尝试
std::mem_fn(&fs::directory_entry::is_regular_file):由于重载歧义,std::mem_fn无法推断出要实例化的模板类型,导致编译失败。
正确实现方式
需要先消除is_regular_file的重载歧义,明确指定无参数的const版本,再用std::mem_fn将成员函数指针适配为可直接调用的对象;成员变量指针可以直接传给std::views::transform(或用std::mem_fn包装):
namespace fs = std::filesystem; std::vector<fs::directory_entry> entries{ fs::directory_iterator("D:\\Path"), fs::directory_iterator() }; std::vector<fs::path> paths; // 明确指定is_regular_file的无参const重载版本 using RegularFileCheck = bool(fs::directory_entry::*)() const; std::ranges::copy(entries | std::views::filter(std::mem_fn(static_cast<RegularFileCheck>(&fs::directory_entry::is_regular_file))) | std::views::transform(&fs::directory_entry::path), std::back_inserter(paths));
或者更紧凑的写法(无需提前定义类型别名):
std::ranges::copy(entries | std::views::filter(std::mem_fn(static_cast<bool(fs::directory_entry::*)() const>(&fs::directory_entry::is_regular_file))) | std::views::transform(std::mem_fn(&fs::directory_entry::path)), std::back_inserter(paths));
补充说明
如果觉得static_cast过于冗长,也可以用C++20的constexpr lambda来实现更简洁的代码(写法几乎无冗余):
constexpr auto is_regular = [](const auto& entry) { return entry.is_regular_file(); }; constexpr auto get_path = [](const auto& entry) { return entry.path(); }; std::ranges::copy(entries | std::views::filter(is_regular) | std::views::transform(get_path), std::back_inserter(paths));
内容的提问来源于stack exchange,提问作者Huw Walters
相关产品推荐
相关产品推荐

