Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I specify an overload when passing an overloaded function to another? [duplicate]

Simple example:

std::vector<std::string> strings{"1","2","3");
std::vector<double> doubles(3);
transform(begin(strings), end(strings), begin(doubles), std::stod);

This fails to compile because the compiler cannot decide which std::stod to use. The one that takes an std::string or the one that takes an std::wstring. We see that only one would work given how std::transform works, but the compiler doesn't.

Options (bad ones)

  • Now, we cannot say std::stod<std::string> because std::stod is not a template but an overload. And even if it was a template, it would have to be a class template with a static non-templated function: Stod<std::string>::stod.
  • What I usually do is use a lambda: [](std::string const& s) { return std::stod(s); } but that is quite a lot of code for nothing.
  • There is also the option to cast the overloaded function to the specific type (double (*)(std::string const&)) but to do that, I have to know the return type. For std::stod that is simple, because it always returns a simple double but for other functions that might be a very complicated thing to write down.

Is there a more concise way than the lambda to select the correct overload or trick the compiler into figuring it out itself?

like image 927
bitmask Avatar asked Sep 12 '25 08:09

bitmask


2 Answers

As you already know, you either resolve the overload upfront by casting, i.e. choosing one of the overloads, or you delay the overload resolution by wrapping the call in a function object (being it a lambda or something else).

The quickest way to take the latter approach, without writing any code of yours, is Boost.Hof's BOOST_HOF_LIFT.

So instead of passing this

std::stod

you pass this

BOOST_HOF_LIFT(std::stod)

Isn't it concise enough?

(Working example on Compiler Explorer.)

like image 200
Enlico Avatar answered Sep 13 '25 22:09

Enlico


  • You would need to help the compiler to select overload:
    static_cast<double(*)(const std::string&, std::size_t*)>(std::stod)
    
  • This does not work anyway. std::stod requires 2 arguments. The default value for the argument doesn't tag along with the function pointer you give to transform to work with.
  • You also take the address of a function in the standard library which isn't allowed (with a few exceptions - but std::stod is not one of them).

The simplest solution for all is to package it in a lambda:

std::transform(std::begin(strings), std::end(strings), std::begin(doubles),
               [](const std::string& s) { return std::stod(s); });

Is there a more concise way than the lambda to select the correct overload or trick the compiler into figuring it out itself?

No, none that is portable.

like image 21
Ted Lyngmo Avatar answered Sep 13 '25 21:09

Ted Lyngmo