[ADT] Allow member pointers in map_range and map_to_vector (#181154)

This is for when all we need is to access a field or call a getter: no
need to write a lambda just to extract these.

Assisted-by: claude
This commit is contained in:
Jakub Kuderski 2026-02-12 14:05:20 -05:00 committed by GitHub
parent 6f51f8e0f9
commit 1f404ec04d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 53 additions and 3 deletions

View File

@ -219,13 +219,13 @@ public:
template <typename... Pn,
std::enable_if_t<std::is_invocable_v<T, Pn...>, int> = 0>
decltype(auto) operator()(Pn &&...Params) {
return (*Obj)(std::forward<Pn>(Params)...);
return std::invoke(*Obj, std::forward<Pn>(Params)...);
}
template <typename... Pn,
std::enable_if_t<std::is_invocable_v<T const, Pn...>, int> = 0>
decltype(auto) operator()(Pn &&...Params) const {
return (*Obj)(std::forward<Pn>(Params)...);
return std::invoke(*Obj, std::forward<Pn>(Params)...);
}
bool valid() const { return Obj != std::nullopt; }
@ -330,7 +330,7 @@ template <typename T> auto drop_end(T &&RangeOrContainer, size_t N = 1) {
template <typename ItTy, typename FuncTy,
typename ReferenceTy =
decltype(std::declval<FuncTy>()(*std::declval<ItTy>()))>
std::invoke_result_t<FuncTy, decltype(*std::declval<ItTy>())>>
class mapped_iterator
: public iterator_adaptor_base<
mapped_iterator<ItTy, FuncTy>, ItTy,
@ -360,6 +360,8 @@ inline mapped_iterator<ItTy, FuncTy> map_iterator(ItTy I, FuncTy F) {
return mapped_iterator<ItTy, FuncTy>(std::move(I), std::move(F));
}
/// Return a range that applies \p F to the elements of \p C. \p F can be a
/// function, lambda, or member pointer.
template <class ContainerTy, class FuncTy>
auto map_range(ContainerTy &&C, FuncTy F) {
return make_range(map_iterator(adl_begin(C), F), map_iterator(adl_end(C), F));

View File

@ -34,6 +34,7 @@ auto filter_to_vector(ContainerTy &&C, PredicateFn &&Pred) {
}
/// Map a range to a SmallVector with element types deduced from the mapping.
/// \p F can be a function, lambda, or member pointer.
template <unsigned Size, class ContainerTy, class FuncTy>
auto map_to_vector(ContainerTy &&C, FuncTy &&F) {
return to_vector<Size>(
@ -41,6 +42,7 @@ auto map_to_vector(ContainerTy &&C, FuncTy &&F) {
}
/// Map a range to a SmallVector with element types deduced from the mapping.
/// \p F can be a function, lambda, or member pointer.
template <class ContainerTy, class FuncTy>
auto map_to_vector(ContainerTy &&C, FuncTy &&F) {
return to_vector(

View File

@ -835,6 +835,22 @@ TEST(STLExtrasTest, DropEndDefaultTest) {
EXPECT_THAT(drop_end(vec), ElementsAre(0, 1, 2, 3));
}
TEST(STLExtrasTest, CallableMemberPointer) {
struct S {
int X;
int getX() const { return X; }
};
S Obj{42};
// Data member pointer.
callable_detail::Callable<int S::*> DataMember(&S::X);
EXPECT_EQ(DataMember(Obj), 42);
// Member function pointer.
callable_detail::Callable<int (S::*)() const> MemFn(&S::getX);
EXPECT_EQ(MemFn(Obj), 42);
}
TEST(STLExtrasTest, MapRangeTest) {
SmallVector<int, 5> Vec{0, 1, 2};
EXPECT_THAT(map_range(Vec, [](int V) { return V + 1; }),
@ -845,6 +861,17 @@ TEST(STLExtrasTest, MapRangeTest) {
some_namespace::some_struct S;
S.data = {3, 4, 5};
EXPECT_THAT(map_range(S, [](int V) { return V * 2; }), ElementsAre(6, 8, 10));
// Pointer to data member.
struct MapRangeStruct {
int X;
int getX() const { return X; }
};
std::vector<MapRangeStruct> Structs = {{1}, {2}, {3}};
EXPECT_THAT(map_range(Structs, &MapRangeStruct::X), ElementsAre(1, 2, 3));
// Pointer to member function.
EXPECT_THAT(map_range(Structs, &MapRangeStruct::getX), ElementsAre(1, 2, 3));
}
TEST(STLExtrasTest, EarlyIncrementTest) {

View File

@ -22,6 +22,25 @@ using testing::ElementsAre;
namespace llvm {
namespace {
TEST(SmallVectorExtrasTest, MapToVector) {
std::vector<int> Numbers = {1, 2, 3};
auto Doubled = map_to_vector(Numbers, [](int X) { return X * 2; });
EXPECT_THAT(Doubled, ElementsAre(2, 4, 6));
// Member pointer.
struct MapToVectorStruct {
int X;
int getX() const { return X; }
};
std::vector<MapToVectorStruct> Structs = {{1}, {2}, {3}};
EXPECT_THAT(map_to_vector(Structs, &MapToVectorStruct::X),
ElementsAre(1, 2, 3));
// Member function pointer.
EXPECT_THAT(map_to_vector(Structs, &MapToVectorStruct::getX),
ElementsAre(1, 2, 3));
}
TEST(SmallVectorExtrasTest, FilterToVector) {
std::vector<int> Numbers = {0, 1, 2, 3, 4};
auto Odd = filter_to_vector<2>(Numbers, [](int X) { return (X % 2) != 0; });