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
The following code compiles with c++11 or higher
#include <iostream>
#include <cstdlib>
#include <cstdio>
#define p 1
// p1: prototype 1
template <class Function, class... Args>
void addv(Function&& f, Args&... args) {
std::cout << f(args...) << std::endl;
}
// p2: prototype 2
template <class Function, class... Args>
void addv(Function& f, Args&... args) {
std::cout << f(args...) << std::endl;
}
int add(int& a, int& b) {
return a+b;
}
class Adder {
public:
int operator () (int& a, int&b) {
return a+b;
}
};
int main() {
int a = 2;
int b = 1;
Adder adder;
addv<int (int&,int&),int,int>(add,a,b); // uses p1 OR p2
addv<Adder,int,int>(Adder(),a,b); // uses p1
addv<Adder,int,int>(adder,a,b); // uses p2
}
If prototype 2 is removed, and this is compiled, the following error happens:
exp.cpp:36:36: error: no matching function for call to ‘addv<Adder, int, int>(Adder&, int&, int&)’
addv<Adder,int,int>(adder,a,b); // uses p2
^
exp.cpp:9:10: note: candidate: template<class Function, class ... Args> void addv(Function&&, Args& ...)
void addv(Function&& f, Args&... args) {
^~~~
exp.cpp:9:10: note: template argument deduction/substitution failed:
exp.cpp:36:36: note: cannot convert ‘adder’ (type ‘Adder’) to type ‘Adder&&’
addv<Adder,int,int>(adder,a,b); // uses p2
^
Why adder cannot be converted from a lvalue to a rvalue implicitly as is needed to have the line addv<Adder,int,int>(adder,a,b); use prototype 1?
Is it possible to explicitly create a rvalue reference of adder to have it correctly match prototype 1?
It can't be converted because the idea with using rvalue and lvalue references in function signatures is exactly to make sure you get one or the other. Not either one.
Normally that is used because if you get an rvalue, you can move it. If you get an lvalue you need to copy it. You can also make sure that a function is only callable with an rvalue, or lvalue.
When passing functions the usual way is to take the parameter by value. That also works with both rvalues and lvalues. This is how it's (almost always?) done in the standard library. Function pointers and Functors are generally very cheap to copy.
If you want a signature that can take both rvalues and lvalues you can use const &.
Also note that since Function&& is a template parameter, it is a forwarding reference. Thats means it will become an rvalue reference or lvalue reference depending on what you pass in.
When you call the function with an explicitly specified parameter though
addv<Adder,int,int>(adder,a,b);
^--this
the template parameter will be deduced to exactly Adder, and your function will then accept only rvalues, since the signature says Function&& -> Adder&&.
The easy way to make the code work is to not explicitly specify the template parameter.
addv(adder,a,b);
Then you can remove prototype 2 and all the function calls will work.
If you really want to or need to specify the parameters, you can use std::move to convert an lvalue to an rvalue at the calling site.
addv<Adder,int,int>(std::move(adder),a,b);
Edit: Convert might be a bit misleading. It's actually a cast. Nothing is changed except the value category.
Your code will compile if you don't explicitly specify template parameters and let template type deduction work it out:
addv(Adder(),a,b); // this is deduced to
// addv<Adder, int, int>(Adder&&, int&, int&)
addv(adder,a,b); // this is deduced to
// addv<Adder&, int, int>(Adder& &&, int&, int&),
// which becomes addv<Adder&, int,int>(Adder&, int&, int&)
// after reference collapsing
So you do want to explicitly specify template parameter, it needs to be
addv<Adder&, int,int>(adder,a,b);
Have a look at Scott Meyers' excellent article on universal reference (and in particular 'reference collapsing'), hope it helps.
Does std::function support perfect forwarding of arguments? I decided to test it:
struct Widget
{
void operator()(int const&)
{
std::cout << "lvalue";
}
void operator()(int&&)
{
std::cout << "rvalue";
}
};
std::function<void(int)> f{Widget()};
int x = 5;
f(x);
Guess which operator() gets called - the one taking rvalue reference. It seems that it is by design. What is the rationale behind this behavior?
Yes and no. Yes, the arguments are forwarded. But no, overload resolution is not done based on the arguments you provide at the point of the call - it's done based on the template arguments to std::function.
std::function<void(int)> means you have a callable that takes an int, which implicitly is an int rvalue. Calling Widget with an rvalue of type int prefers the int&& overload over the int const& overload, which is why that one is selected. It doesn't matter how you invoke the actual function object, once you selected that you want void(int) - that's the preferred overload.
The actual call operator behaves as if:
struct widget_function {
void operator()(int arg) const {
// ~~~~~ ~~~~
w_(std::forward<int>(arg));
// ~~~
}
Widget w_;
};
The underlined portions come from the signature you provide to std::function. You can see that both f(x) and f(5) end up calling the same operator() from Widget.
In short, std::function<Sig> type erases one single overload that satisfies Sig. It does not type erase an entire overload set. You asked for void(int), so you get void(int) and only void(int).
I have the following piece of code:
#include <functional>
struct X {
int get() const& {
return 42;
}
};
template<typename Func>
std::result_of_t<Func(X)> Apply(Func fn) {
X x;
return fn(x);
}
int main(void) {
Apply([](X const& x){return x.get();});
//Apply(std::mem_fn(&X::get)); // does not compile
}
The first call to Apply compiles fine, but if I uncomment the second call, I get the following compilation error:
main.cpp:16:5: error: no matching function for call to 'Apply'
Apply(std::mem_fn(&X::get)); // does not compile
^~~~~
main.cpp:10:27: note: candidate template ignored: substitution failure [with Func = std::_Mem_fn<int (X::*)() const &>]: no type named 'type' in 'std::result_of<std::_Mem_fn<int (X::*)() const &> (X)>'
std::result_of_t<Func(X)> Apply(Func fn) {
^
I somehow expected that both calls could be used interchangeably and that std::mem_fn just "would do the right thing". Can anybody explain, what happens here?
The problem is here:
int get() const& {
// ^^^
Your member function is lvalue-reference qualified. In your Apply():
template<typename Func>
std::result_of_t<Func(X)> Apply(Func fn) {
return fn(X{});
}
you're invoking it with an rvalue. Which brings us to the [very surprising to me] difference between these two expressions:
X{}.get(); // ok
(X{}.*&X::get)(); // ill-formed
On specifically pointer-to-member operators, the ref-qualifiers of the member pointer are checked against the value category of the object. From [expr.mptr.oper]:
In a .* expression whose object expression is an rvalue, the program is ill-formed if the second operand is a pointer to member function with ref-qualifier &. In a .* expression whose object expression is an lvalue, the
program is ill-formed if the second operand is a pointer to member function with ref-qualifier &&.
So the first expression is okay, get() is const&-qualified but rvalues can bind to that. The second expression is not okay - the rules just explicitly prohibit it.
So the behavior you see is perfectly correct - mem_fn is defined by directly invoking the member function, which is ill-formed on an rvalue, so Apply is removed from the overload set. If it were not, then instantiating the body would be a hard error.
The reason the lambda works is that the temporary X is bound to the lambda's reference parameter. get() is then invoked on the lvalue function parameter - not on the temporary passed into it. But even without that, invoking get() directly on the temporary would still be fine.
I am writing a library with many function objects whose classes have several operator() overloads that do not depend on the state of the classes and do not alter it. Now, I tried to make my code work with many old-style APIs (it is not a random need, I actually had to deal with such APIs) and therefore decided to make the function objects convertible to any function pointer corresponding to one of the overloads. At some point, I realized that I had too many such conversions to function pointer operators and that I should theorically be able to write a single variadic conversion operator. Here is a class implementing such a variadic operator:
struct foobar
{
template<typename... Args>
using fptr_t = void(*)(Args... args);
template<typename... Args>
operator fptr_t<Args...>() const
{
return [](Args... args) {
// Whatever
};
}
};
As you can see, I used the lambda conversion to function pointer to implement the conversion operator, which is not a problem since every function object I have is stateless. The goal was to be able to use the class as follows:
int main()
{
void(*foo)(int) = foobar();
void(*bar)(float, double) = foobar();
}
g++ has no problem compiling this code with the expected semantics. However, clang++ rejects it with a template substitution failure error:
main.cpp:21:11: error: no viable conversion from 'foobar' to 'void (*)(int)'
void(*foo)(int) = foobar();
^ ~~~~~~~~
main.cpp:11:5: note: candidate function [with Args = int]
operator fptr_t<Args...>() const
^
1 error generated.
Note that clang++ has no problem with such conversion operators as long as no variadic templates are involved. If I use a single template parameter, it will have no problem compiling the code. Now, should the code above be accepted or rejected by the compiler?
A lambda can only be converted to a function pointer if it does not capture, so your code should work. This is justified in the standard 5.1.2/p6 Lambda expressions [expr.prim.lambda] (Emphasis Mine):
The closure type for a non-generic lambda-expression with no
lambda-capture has a public non-virtual non-explicit const conversion
function to pointer to function with C++ language linkage (7.5) having
the same parameter and return types as the closure type’s function
call operator. The value returned by this conversion function shall be the
address of a function that, when invoked, has the same effect as invoking the
closure type’s function call operator.
So I would file it as a CLANG bug.
As a work around for CLANG, you can convert it to a std::function as shown below:
struct foobar
{
template<typename... Args>
using fptr_t = void(*)(Args... args);
template<typename... Args>
operator std::function<void(Args...)>() const
{
return [](Args... args) {
//...
};
}
};
int main()
{
std::function<void(int)> f1 = foobar();
std::function<void(double, float)> f2 = foobar();
f1(1);
f2(2.0, 1.0f);
}
Live Demo