Reputation: 13471
I have a class similar to this that is supposed to take a function object and use it later:
template<typename F>
class A {
public:
A(const F& f) : _f(f) {}
A(F&& f) : _f(std::move(f)) {}
private:
F _f;
};
I also define a convenience initialization function and a dummy test function:
template<typename F>
A<F> MakeA(F&& f) {
return A<F>(std::forward<F>(f));
}
void foo() {}
I get an error that it is not possible to overload A<F>::A(F&&)
with A<F>::A(const F&)
for F = void(&)()
when I call:
auto a = MakeA(foo);
I understand that I can fix it by having function pointer instead of function reference and also lambdas work nicely:
auto a1 = MakeA(&foo);
auto a2 = MakeA([]{});
What is special about function references and why overloading does not work there?
Upvotes: 3
Views: 181
Reputation: 157424
The error message from clang is more illuminating:
6 : error: multiple overloads of 'A' instantiate to the same signature 'void (void (&&)())'
This is because for any lvalue reference type T = U&
, T&&
and T const&
are the same type, per the reference-collapsing rules in [dcl.ref]:
6 - If [...] a type TR [is] a reference to a type T, an attempt to create the type “lvalue reference to cv TR” creates the type “lvalue reference to T”, while an attempt to create the type “rvalue reference to cv TR” creates the type TR [...]
using T = int&;
static_assert(std::is_same<T&&, T const&>::value, "!!");
The real problem is that you're applying the "universal reference / std::forward
" pattern outside its region of applicability; it is appropriate only for perfect forwarding of arguments. Your code will also break if you pass a lambda lvalue:
auto l = []{};
auto d = MakeA(l); // breaks
The correct way to write a type-deducing construction function is to apply decay
to the type of the argument (cf. make_optional
):
template<typename F>
A<typename std::decay<F>::type> MakeA(F&& f) {
return A<typename std::decay<F>::type>(std::forward<F>(f));
}
Upvotes: 4
Reputation: 217990
With F = void(&)()
, F&&
and const F&
are the same type thus the error.
Upvotes: 1