Std::Bind Overload Resolution

std::bind overload resolution

You need a cast to disambiguate the overloaded function:

(int(A::*)(int,int))&A::operator()

use std::bind with overloaded functions

You may use:

auto f_binder = std::bind(static_cast<double(&)(double)>(f), 2.);

or

auto f_binder = bind<double(double)>(f, 2.);

Alternatively, lambda can be used:

auto f_binder = []() {
return f(2.); // overload `double f(double)` is chosen as 2. is a double.

};

C++ Bind failure due to unable to resolve overloaded function

You can't pass a function name that designates an overload set as a function pointer. There are several ways to mitigate this. One is a lambda:

transform(data.cbegin(),data.cend(),result.begin(),
[](int d){ return std::pow(d, 2); });

Another one is to explicitly cast the overload set to the specific function you intend to invoke:

transform(data.cbegin(),data.cend(),result.begin(),
bind(static_cast<double(*)(double, int)>(std::pow),_1,2));

A third way is to use one of the "lift" macros available, that wrap overload sets into lambdas.

#include <boost/hof/lift.hpp>

transform(data.cbegin(),data.cend(),result.begin(),
bind(BOOST_HOF_LIFT(std::pow),_1,2));

Note that in all snippets, I have changed the third parameter into result.begin(), as std::transform needs an output iterator there, and the first and second to act on const_iterators.

Why doesn't std::function participate in overload resolution?

This doesn't really have anything to do with "phases of translation". It's purely about the constructors of std::function.

See, std::function<R(Args)> doesn't require that the given function is exactly of the type R(Args). In particular, it doesn't require that it is given a function pointer. It can take any callable type (member function pointer, some object that has an overload of operator()) so long as it is invokable as if it took Args parameters and returns something convertible to R (or if R is void, it can return anything).

To do that, the appropriate constructor of std::function must be a template: template<typename F> function(F f);. That is, it can take any function type (subject to the above restrictions).

The expression baz represents an overload set. If you use that expression to call the overload set, that's fine. If you use that expression as a parameter to a function that takes a specific function pointer, C++ can whittle down the overload set to a single call, thus making it fine.

However, once a function is a template, and you're using template argument deduction to figure out what that parameter is, C++ no longer has the ability to determine what the correct overload in the overload set is. So you must specify it directly.

std::function std::bind with lambda overload ambiguity

This is about the most unhelpful compiler error ever. The problem is that you want

func = std::bind([this](my_struct& s) { s.i = 5; }, std::placeholders::_1);
// ^^^^^^^^^^^^^^^^^^^^^

std::bind(f) means "give me a g such that g(/* anything */) is f().

You need to use placeholders if you want to pass arguments through.

(I assume that your real code does something more complicated than this, because there's no need for bind or for capturing this in the code you've shown.)

Why won't std::bind compile when bound to a member function?

It happens because you have overloaded the function, and std::bind is not aware of function signatures and so can't distinguish between them.

Easy solution? Rename of of the functions.

Less easy solution: Cast the pointer to the function to the correct type.

Overload resolution with std::function

In C++11...

Let's take a look at the specification of the constructor template of std::function (which takes any Callable): [func.wrap.func.con]/7-10

template<class F> function(F f);
template <class F, class A> function(allocator_arg_t, const A& a, F f);

7 Requires: F shall be CopyConstructible. f shall be Callable (20.10.11.2) for argument types ArgTypes and return type
R. The copy constructor and destructor of A shall not throw
exceptions.

8 Postconditions: !*this if any of the following hold:

  • f is a NULL function pointer.
  • f is a NULL pointer to member.
  • F is an instance of the function class template, and !f

9 Otherwise, *this targets a copy of f initialized with std::move(f). [left out a note here]

10 Throws: shall not throw exceptions when f is a function pointer or a reference_wrapper<T> for some T. Otherwise, may throw
bad_alloc or any exception thrown by F’s copy or move constructor.

Now, constructing, or attempting to construct (for overload resolution) a std::function<void(int)> from a [](){} (i.e. with signature void(void)) violates the requirements of std::function<void(int)>'s constructor.

[res.on.required]/1

Violation of the preconditions specified in a function’s Requires: paragraph results in undefined behavior unless the function’s Throws: paragraph specifies throwing an exception when the precondition is violated.

So, AFAIK, even the result of the overload resolution is undefined. Therefore, both versions of g++/libstdc++ are complying in this aspect.


In C++14, this has been changed, see LWG 2132. Now, the converting constructor template of std::function is required to SFINAE-reject incompatible Callables (more about SFINAE in the next chapter):

template<class F> function(F f);
template <class F, class A> function(allocator_arg_t, const A& a, F f);

7 Requires: F shall be CopyConstructible.

8 Remarks: These constructors shall not participate in overload
resolution unless f is Callable (20.9.11.2) for argument types
ArgTypes... and return type R.

[...]

The "shall not participate in overload resolution" corresponds to rejection via SFINAE. The net effect is that if you have an overload set of functions foo,

void foo(std::function<void(double)>);
void foo(std::function<void(char const*)>);

and a call-expression such as

foo([](std::string){}) // (C)

then the second overload of foo is chosen unambiguously: Since std::function<F> defines F as its interface to the outside, the F defines which argument types are passed into std::function. Then, the wrapped function object has to be called with those arguments (argument types). If a double is passed into std::function, it cannot be passed on to a function taking a std::string, because there's no conversion double -> std::string.
For the first overload of foo, the argument [](std::string){} is therefore not considered Callable for std::function<void(double)>. The constructor template is deactivated, hence there's no viable conversion from [](std::string){} to std::function<void(double)>. This first overload is removed from the overload set for resolving the call (C), leaving only the second overload.

Note that there's been a slight change to the wording above, due to LWG 2420: There's an exception that if the return type R of a std::function<R(ArgTypes...)> is void, then any return type is accepted (and discarded) for the Callable in the constructor template mentioned above. For example, both []() -> void {} and []() -> bool {} are Callable for std::function<void()>. The following situation therefore produces an ambiguity:

void foo(std::function<void()>);
void foo(std::function<bool()>);

foo([]() -> bool {}); // ambiguous

The overload resolution rules don't try to rank among different user-defined conversions, and hence both overloads of foo are viable (first of all) and neither is better.


How can SFINAE help here?

Note when a SFINAE-check fails, the program isn't ill-formed, but the function isn't viable for overload resolution. For example:

#include <type_traits>
#include <iostream>

template<class T>
auto foo(T) -> typename std::enable_if< std::is_integral<T>::value >::type
{ std::cout << "foo 1\n"; }

template<class T>
auto foo(T) -> typename std::enable_if< not std::is_integral<T>::value >::type
{ std::cout << "foo 2\n"; }

int main()
{
foo(42);
foo(42.);
}

Similarly, a conversion can be made non-viable by using SFINAE on the converting constructor:

#include <type_traits>
#include <iostream>

struct foo
{
template<class T, class =
typename std::enable_if< std::is_integral<T>::value >::type >
foo(T)
{ std::cout << "foo(T)\n"; }
};

struct bar
{
template<class T, class =
typename std::enable_if< not std::is_integral<T>::value >::type >
bar(T)
{ std::cout << "bar(T)\n"; }
};

struct kitty
{
kitty(foo) {}
kitty(bar) {}
};

int main()
{
kitty cat(42);
kitty tac(42.);
}

Why isn't overload resolution picking the std::vector overload of my template function?

The type deduced by the forwarding reference is std::vector<int>&, as opposed to the const std::vector<int>& of the other overload. So when comparing the overloads, your non-const argument is a better match for the non-const qualified reference parameter, and so that one is chosen.

One way to address it is to account for both const qualifications with the help of another overload.

template<typename T>
std::string f(std::vector<T>& member) {
return f(std::as_const(member));
}

Here we obtain a const reference to member with the help of std::as_const and delegate to your original overload. You may want to provide an rvalue specific overload too, since the forwarding reference will deduce a better match for those as well when compared to your vector overloads.



Related Topics



Leave a reply



Submit