1

For example, std::get<N>.

Can I do the following without using a lambda somehow?

#include <iostream>
#include <tuple>
#include <algorithm>
#include <vector>
#include <iostream>

using str_and_int = std::tuple<std::string, int>;

std::vector<std::string> just_strings(const std::vector<str_and_int>& tuples) {
    std::vector<std::string> strings(tuples.size());
    std::transform(tuples.begin(), tuples.end(), strings.begin(),
        [](const auto& tup) {
            return std::get<0>(tup);
        }
    );
    return strings;
}

int main()
{
    std::vector<str_and_int> foo = { {"foo",1}, {"bar",2} ,{"quux",3}, {"mumble",4} };
    for (const auto& str : just_strings(foo)) {
        std::cout << str << "\n";
    }
    return 0;
}

Changing it to

std::transform(tuples.begin(), tuples.end(), strings.begin(), std::get<0, str_and_int>)

does not work. I am guessing because std::get is overloaded?

jwezorek
  • 8,592
  • 1
  • 29
  • 46
  • You can pass a function pointer if that helps. (So first try to store the function pointer in a variable and see what error you have.) – lorro Jul 01 '22 at 15:35
  • 1
    @lorro but you can't take the address of [most functions in `std`](https://stackoverflow.com/questions/55687044/can-i-take-the-address-of-a-function-defined-in-standard-library) – Caleth Jul 01 '22 at 15:42
  • 1
    why do you want to avoid using a lambda? I mean you can write your custom function or functor, but not sure if thats what you are looking for. – 463035818_is_not_an_ai Jul 01 '22 at 15:44
  • yeah `std::string(*fn)(const str_and_int&) = std::get<0, str_and_int>;` yields basically the same error. Visual Studio says "cannot convert from overloaded function" – jwezorek Jul 01 '22 at 15:44
  • because I tend to always use lambdas when using the standard algorithms even when I don't have to and I am trying to get out of that habit. Like if you have a free function that has the signature a standard algorithm needs you should just use that, not wrap it in a lambda. I am going through code and removing redundant lambdas. This case I can't fix though but like std::get<0> here should instantiate to some kind of callable that can be used I just dont know if there is syntax that allows using that callable. – jwezorek Jul 01 '22 at 15:48
  • 2
    the callable you are looking for is the lambda. Lambdas play extremely well with compiler optimizations like inlining, I doubt you can find something better – 463035818_is_not_an_ai Jul 01 '22 at 15:51

2 Answers2

3

You don't have to use a lambda. You could provide an instance of your own type if you'd like:

struct transformer {
    auto operator()(const auto& tup) const { // auto C++20
        return std::get<0>(tup);
    }
};

std::vector<std::string> just_strings(const std::vector<str_and_int>& tuples) {
    std::vector<std::string> strings(tuples.size());
    std::transform(tuples.begin(), tuples.end(), strings.begin(), transformer{});
    return strings;
}
Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
  • this answers the question as asked but i think the real answer i was looking for is no. if it is not allowed to get a pointer to a function in the standard library then when you pass one as an argument you have to wrap it in something, like in this answer or in a lambda. There's no magic syntax to refer to what std::get<0> instantiates into in the code in the question though. – jwezorek Jul 01 '22 at 16:16
  • @jwezorek No, that's true. I've taken the address of standard functions myself in the past (before I realized I shouldn't) and I got so surprised that it worked in some cases in some implementations and not in others. – Ted Lyngmo Jul 01 '22 at 16:23
0

Because it is illegal to get a pointer to a function in the standard library, a less verbose option if you are doing this sort of thing multiple times is to wrap the call in a function template. For example,

#include <iostream>
#include <tuple>
#include <algorithm>
#include <vector>
#include <iostream>

using str_and_int = std::tuple<std::string, int>;

template <typename T>
auto first(const T& tup) {
    return std::get<0>(tup);
}

std::vector<std::string> just_strings(const std::vector<str_and_int>& tuples) {
    std::vector<std::string> strings(tuples.size());
    std::transform(tuples.begin(), tuples.end(), strings.begin(), first<str_and_int> );
    return strings;
}

int main()
{
    std::vector<str_and_int> foo = { {"foo",1}, {"bar",2} ,{"quux",3}, {"mumble",4} };
    for (const auto& str : just_strings(foo)) {
        std::cout << str << "\n";
    }
    return 0;
}
jwezorek
  • 8,592
  • 1
  • 29
  • 46