For the below code, I get the error
#include <iostream>
#include <functional>
using namespace std;
class A {};
class B {};
namespace N
{
void func(A a, int z){}
void func(B a, int z){}
}
void func_1(std::function<void(A, int)> x)
{
A a;
x(a, 1);
}
int main()
{
func_1(N::func);
return 0;
}
Error:
main.cpp:23:19: error: cannot resolve overloaded function 'func' based on conversion to type 'std::function<void(A, int)>'
23 | func_1(N::func);
If we do the static cast for the func_1(N::func); as func_1(static_cast<void (&)(A, int)>(N::func));, then this work fine. But I would expect this to work without a cast.
std::function<void(A, int)> is more complicated than void(*)(A, int).
template< class F >
function( F f );
Initializes the target with std::move(f). If f is a null pointer to function or null pointer to member, *this will be empty after the call. This constructor does not participate in overload resolution unless f is Callable for argument types Args... and return type R.
You don't even know what constructors participate in overload resolution until you decide which N::func you mean.
One can conceive of an combined overload resolution and template argument deduction scheme that could "meet in the middle" by trying std::function<void(A, int)>::function<void(*)(A, int)> among (arbitrarily many) other valid instantiations of the constructor.
Problems abound with that.
It has to provably arrive at an answer. In general there are infinite possible instantiations of the templates. You'd also want it to be able to pick int(*)(A, int) if you passed it int g(A, int).
It really should agree with the current scheme where that arrives at an unambiguous answer.
Each of the compiler vendors have to implement it correctly.
As a handy workaround you can provide this kind of func_1 overload.
...
void func_1(void(*x)(A, int))
{
func_1(std::function<void(A, int)>{x});
}
Now it works as desired without static_cast: demo
Related
I have this example about std::function:
int add(int x, int y, int z) {return x + y + z;}
int add(int a, int b) {return a + b;}
int main()
{
std::function<int(int, int)> fn = add; // error
int(*pfn)(int, int) = add; // OK
fn = pfn; // ok fn is bound to add(int, int)
std::cout << fn(5, 7) << std::endl; // 12
}
Why Overload resolution doesn't resolve which version of add when initializing fn but is able to initialize the function pointer pfn?
Is there a workaround rather than using function pointer to decide which version of an overloaded function as an initializer to an std::function object?
Why Overload resolution doesn't resolve which version of add when initializing fn but is able to initialize the function pointer pfn?
Because overload resolution is performed in the initialization of function pointer (like pfn), based on the type of the function pointer.
In all these contexts, the function selected from the overload set is the function whose type matches the pointer to function, reference to function, or pointer to member function type that is expected by target: the object or reference being initialized, the left-hand side of the assignment, function or operator parameter, the return type of a function, the target type of a cast, or the type of the template parameter, respectively.
On the other hand, such overload resolution doesn't happen when initializing a std::function, which has a constructor template and the template parameter needs to be deduced from the function argument; the compiler can't choose one for the deduction.
As the workaround, you can apply static_cast to specify the overload you want explicitly.
static_cast may also be used to disambiguate function overloads by performing a function-to-pointer conversion to specific type
std::function<int(int, int)> fn = static_cast<int(*)(int, int)>(add);
For the function pointer case, C++ has a special rule that permits a sort of "time travelling" lookup. It can perform overload resolution on a name, based on what you're going to assign/initialise the name to.
This is basically a hack built into the language (rules in [over.over]).
No other part of the language works this way. For example, where newcomers often expect that after writing float x = 1/2 the value of x will be 0.5, we have to explain that the fact you're initialising a float has no relevance to the types or calculation of the expression 1/2.
This hack was not extended to std::function. Presumably that is because adding hacks is bad, and because it is not needed for this case. Why not? Because you can still deploy the hack indirectly with a static_cast on the RHS of your std::function initialisation:
std::function<int(int, int)> fn = static_cast<int(*)(int, int)>(add);
… and there's your workaround.
I have two overloads of a function foo which take different std::functions which results in an ambiguity issue for the latter when used with the result of a std::bind. I don't understand why only this is ambiguous.
void foo(std::function<void(int)>) {}
void foo(std::function<int()>) {}
void take_int(int) { }
int ret_int() { return 0; }
When using int() with a bind function I get an ambiguity error
foo(std::bind(ret_int)); // ERROR
With the gcc-5.1 error (and similar with clang)
error: call to 'foo' is ambiguous
foo(std::bind(ret_int));
^~~
note: candidate function
void foo(std::function<void(int)>) {}
^
note: candidate function
void foo(std::function<int()>) {}
However all of the following work
foo(std::bind(take_int, _1));
foo(take_int);
foo(ret_int);
foo([](){ return ret_int(); });
struct TakeInt {
void operator()(int) const { }
};
struct RetInt {
int operator()() const { return 0; }
};
foo(TakeInt{});
foo(RetInt{});
Looking at the std::function constructor
template< class F >
function( F f );
it would make sense to me that any function with multiple overloads on different std::function types should have ambiguities, but it's only an issue with the call to bind. I then thought "maybe there's some magic happening to handle function types and lambdas and it doesn't deal with actual classes," but it handles those too.
There's a note on en.cppreference that says [since c++14]
This constructor does not participate in overload resolution unless f is Callable for argument types Args... and return type R
The problem exists in how bind is allowed to be called. As cppreference states
If some of the arguments that are supplied in the call to g() are not matched by any placeholders stored in g, the unused arguments are evaluated and discarded.
In other words, you need to pass at least as many arguments as the underlying callable expects.
This means that the following is valid
int f();
auto b = std::bind(f);
b(1, 2, 3); // arguments aren't used
So saying
auto b = std::bind(ret_int)
b(1);
Works, with the 1 discarded, therefore the following is valid, and overload selection becomes ambiguous
std::function<void(int)> f = std::bind(ret_int);
The inverse is not true, however
std::function<int()> f = std::bind(take_int);
because take_int cannot be called with no arguments.
Takeaway: lambda > bind
I am trying to understand why std::function is not able to distinguish between overloaded functions.
#include <functional>
void add(int,int){}
class A {};
void add (A, A){}
int main(){
std::function <void(int, int)> func = add;
}
In the code shown above, function<void(int, int)> can match only one of these functions and yet it fails. Why is this so? I know I can work around this by using a lambda or a function pointer to the actual function and then storing the function pointer in function. But why does this fail? Isn't the context clear on which function I want to be chosen? Please help me understand why this fails as I am not able to understand why template matching fails in this case.
The compiler errors that I get on clang for this are as follows:
test.cpp:10:33: error: no viable conversion from '<overloaded function type>' to
'std::function<void (int, int)>'
std::function <void(int, int)> func = add;
^ ~~~
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__functional_03:1266:31: note:
candidate constructor not viable: no overload of 'add' matching
'std::__1::nullptr_t' for 1st argument
_LIBCPP_INLINE_VISIBILITY function(nullptr_t) : __f_(0) {}
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__functional_03:1267:5: note:
candidate constructor not viable: no overload of 'add' matching 'const
std::__1::function<void (int, int)> &' for 1st argument
function(const function&);
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__functional_03:1269:7: note:
candidate template ignored: couldn't infer template argument '_Fp'
function(_Fp,
^
1 error generated.
EDIT - In addition to MSalters' answer, I did some searching on this forum and found the exact reason why this fails. I got the answer from Nawaz's reply in this post.
I have copy pasted from his answer here:
int test(const std::string&) {
return 0;
}
int test(const std::string*) {
return 0;
}
typedef int (*funtype)(const std::string&);
funtype fun = test; //no cast required now!
std::function<int(const std::string&)> func = fun; //no cast!
So why std::function<int(const std::string&)> does not work the way funtype fun = test works above?
Well the answer is, because std::function can be initialized with any object, as its constructor is templatized which is independent of the template argument you passed to std::function.
It's obvious to us which function you intend to be chosen, but the compiler has to follow the rules of C++ not use clever leaps of logic (or even not so clever ones, as in simple cases like this!)
The relevant constructor of std::function is:
template<class F> function(F f);
which is a template that accepts any type.
The C++14 standard does constrain the template (since LWG DR 2132) so that it:
shall not participate in overload resolution unless f is Callable (20.9.12.2) for argument types ArgTypes... and return type R.
which means that the compiler will only allow the constructor to be called when Functor is compatible with the call signature of the std::function (which is void(int, int) in your example). In theory that should mean that void add(A, A) is not a viable argument and so "obviously" you intended to use void add(int, int).
However, the compiler can't test the "f is Callable for argument types ..." constraint until it knows the type of f, which means it needs to have already disambiguated between void add(int, int) and void add(A, A) before it can apply the constraint that would allow it to reject one of those functions!
So there's a chicken and egg situation, which unfortunately means that you need to help the compiler out by specifying exactly which overload of add you want to use, and then the compiler can apply the constraint and (rather redundantly) decide that it is an acceptable argument for the constructor.
It is conceivable that we could change C++ so that in cases like this all the overloaded functions are tested against the constraint (so we don't need to know which one to test before testing it) and if only one is viable then use that one, but that's not how C++ works.
While it's obvious what you want, the problem is that std::function cannot influence overload resolution of &add. If you were to initialize a raw function pointer (void (*func)(int,int) = &add), it does work. That's because function pointer initialization is a context in which overload resolution is done. The target type is exactly known. But std::function will take almost any argument that's callable. That flexibility in accepting arguments does mean that you can't do overload resolution on &add. Multiple overloads of add might be suitable.
An explicit cast will work, i.e. static_cast<void(*)(int, int)> (&add).
This can be wrapped in a template<typename F> std::function<F> make_function(F*) which would allow you to write auto func = make_function<int(int,int)> (&add)
Try:
std::function <void(int, int)> func = static_cast<void(*)(int, int)> (add);
Addresses to void add(A, A) and void add(int, int) obvoiusly differes. When you point to the function by name it is pretty much imposible for compiler to know which function address do you need. void(int, int) here is not a hint.
Another way to deal with this is with a generic lambda in C++14:
int main() {
std::function<void(int, int)> func = [](auto &&... args) {
add(std::forward<decltype(args)>(args)...);
};
}
That will create a lambda function that will resolve things with no ambiguity.
I did not forward arguments,
As far as I can see, it's a Visual Studio problem.
c++11 standard (20.8.11)
std::function synopsis
template<class R, class... ArgTypes> class function<R(ArgTypes...)>;
but VisualStudio doesn't have that specialization
clang++ and g++ are perfectly fine with overloading std::functions
prior answers explain why VS doesn't work, but they didn't mention that it's VS' bug
So I was taking a look through http://en.cppreference.com/w/cpp/types/result_of and saw the syntax for doing result_of of a member function and I just don't understand what is going on with that decltype.
Why do the args come after the decltype? Wouldn't they be important in figuring out the type of the member function? In my mind I imagine that instead of decltype(&C::Func)(C, char, int&) it should be decltype(&C::Func(C, char, int&)) or something of the like, but I'm having a hard time wrapping my head around it. Can anyone please explain why it is this syntax?
std::result_of takes a template argument of the form F(A...). F should be a type that is callable, such as a function type or a class type with an overloaded operator(). A... should be a sequence of argument types.
Therefore, if you have some expression e and some argument types A... and you want to know what result type you will get if you call e with arguments of types A... then you would put F = decltype(e) in std::result_of<F(A...)>, that is, std::result_of<decltype(e)(A...)>.
I'm copying the relevant code from the example that you pointed to:
#include <type_traits>
struct C {
double Func(char, int&);
};
int main()
{
// result_of can be used with a pointer to member function as follows
std::result_of<decltype(&C::Func)(C, char, int&)>::type g = 3.14;
static_assert(std::is_same<decltype(g), double>::value, "");
}
decltype(&C::Func) is the declared type of method Func of C, which is a function taking a C reference (corresponding to this), a char and an int reference.
Let us call this type T.
Then, result_of<T(...)>::type will be the type of the result of applying a function of type T to the arguments whose types you specify in the parentheses.
Therefore, in this example, result_of<decltype(&C::Func)(C, char, int&)>::type will be double.
As you are aware, the type T1(T2,T3) means a function returning a value of T1 and taking arguments of type T2 and T3. As soon as you are working with values of that type, you are bound to that interpretation.
std::result_of does not deal with any values, just with a type of the form T1(T2,T3), so it technically has the freedom to interpret the types any way it likes. And it actually does! If std::result_of would be parametrized over the type of a function, and return the return type of that function, the result (i.e. nested type member) would just be T1, but it isn't. The standard writers chose to implement a different functionality: std::result_of takes the type T1 in it's type parameter not to be the return type of the function to be determined, but the complete type of some callable thing (e.g. a function pointer), and it will return the type returned by that callable thing when passed the arguments T1 and T2.
Example time!
#include <iostream>
#include <ostream>
#include <type_traits>
#include <typeinfo>
int main(void)
{
// define the type of a function
typedef int ftype(char, long);
// (A) doesn't compile: you can't call an int
std::cout << typeid(std::result_of<int(char,long)>).name() << '\n';
// (B) doesn't compile: A the return type of a function may not be a function
std::cout << typeid(std::result_of<ftype(char,long)>::type).name() << '\n';
// (C) does compile and print the typeid name of int. On g++ this is "i"
std::cout << typeid(std::result_of<ftype*(char,long)>::type).name() << '\n';
}
Case (A) fails, as int is not callable, although the template parameter itself is well-formed. Case (B) fails, as the template parameter is not well-formed. In T1(T2,T3), T1 must not be a function type, as types describing a function returning a function are forbidden. Case (C) has a valid template parameter, in which the return type of the "function" describes a callable type, so std::result_of is applicable.
With this context in mind, the answer to your question is likely obvious. The expression decltype(&C::Func)(C, char, int&) describes a function type returning decltype(&C::Func) and taking the parameter types C, char and int &. As already discussed, the return type has to be something callable, which is the case for decltype(&C::Func), as it is the pointer-to-member-function type double (C::*)(char, int&). According to the definition of the INVOKE operation (see the page about callable), this type is callable with a parameter list (C, char, int&), so the application std::result_of to decltype(&C::Func)(C, char, int&) is valid.
The alternative you suggest: std::result_of<decltype(&C::Func(C, char, int&))> is not valid, as &C::Func(C, char, int&) is not a valid expression. If you want to constrain the type (in case there are multiple overloads of Func), you can do that using a cast, though. decltype(static_cast<double (C::*)(int, char&)>(&C::Func)) is a valid expression, returning (no surprise there) the type double (C::*)(int, char&). But like in example (A), this is not a type you may apply std::result_of on.
The really interesting use-case for std::result_of is the case in which T1, the callable type, is a function object. By passing the type of a function object to std::result_of as T1, you are passing all function-call operators of that object at the same time and you can have std::result_of pick the right one using overload resolution. Passing "all the Func functions" like you pass "all the operator() functions" is not possible, because std::result_of is hardwired to look for operator() in case of objects, and you can't use the address-of operator to map operator() invocations to Func() invocations. You can write a template doing this mapping, though:
#include <iostream>
#include <ostream>
#include <type_traits>
#include <typeinfo>
class S {
public:
int Func(int);
double Func(float, float);
};
template <typename T>
class call_Func : public T {
public:
template<typename... args>
auto operator()(args... vals) -> decltype(this->Func(vals...)) { return this->Func(vals...); }
};
int main(void)
{
std::cout << typeid(std::result_of<call_Func<S>(int)>::type).name() << '\n';
}
The template call_Func redirects calling operator() on call_Func<S> to calling Func on the base class S (one should use std::forward, though), but note you can not write a "generic redirector" that gets the name of the function to redirect the function call operator to as template parameter, as you can neither pass overload set nor names as template parameters, but just types and constant values (for non-type parameters). Pointer-to-member-functions are one kind of constant value, but you already lost the overloading as soon as you form such a pointer.
I am using a class that needs some kind of callback method, so i'm using boost::function to store the function pointers.
i need the callback to have one optional argument, but i found out that boost::function won't let me define optional arguments kind of type, so i tried the following code and it worked..
//the second argument is optional
typedef boost::function< int (int, char*)> myHandler;
class A
{
public:
//handler with 2 arguments
int foo(int x,char* a) {printf("%s\n",a); return 0;};
//handler with 1 argument
int boo(int x) {return 1;};
}
A* a = new A;
myHandler fooHandler= boost::bind(&A::foo,a,_1,_2);
myHandler booHandler= boost::bind(&A::boo,a,_1);
char* anyCharPtr = "just for demo";
//This works as expected calling a->foo(5,anyCharPtr)
fooHandler(5,anyCharPtr);
//Surprise, this also works as expected, calling a->boo(5) and ignores anyCharPtr
booHandler(5,anyCharPtr);
I was shocked that it worked, question is should it work, and is it legit?
is there a better solution?
Arguably a type safety hole in the bind -> function conversion.
boost::bind doesn't return an std::function but a function object of a very complicated type. In the case of
boost::bind(&A::boo,a,_1);
as seen above, the returned object has type
boost::_bi::bind_t<
int,
boost::_mfi::mf1<int,A,int>,
boost::_bi::list2<boost::_bi::value<A*>, boost::arg<1> >
>
std::function only checks that the supplied function object is "compatible", in this case, whether it is callable with an int as the first argument and a pointer to char as the second argument. Upon examining the *boost::bind_t* template, we see that it does indeed have a matching function call operator:
template<class A1, class A2> result_type operator()(A1 & a1, A2 & a2)
Inside this function the second argument ends up being silently discarded. This is by design. From the documentation: Any extra arguments are silently ignored (...)