Overloaded function templates with reference parameters - c++

template <typename T> void f(T&) {}
template <typename T> void f(T&&) {}
int main()
{
int x;
f(x); //ambiguous
}
Why is this call ambiguous? The first template specialization is f<int>(int&), and the second is f<int&>(int&). As the parameters are the same, the function template, which is more specialzed according to the partial ordering rules, is better. Then according to Standard 14.8.2.4/9
If, for a given type, deduction succeeds in both directions (i.e., the types are identical after the transformations above) and both P and A were reference types (before being replaced with the type referred to above):
— if the type from the argument template was an lvalue reference and the type from the parameter template was not, the argument type is considered to be more specialized than the other; ...
The first template has T& and the second has T&&, so the first should be more specialized. What is wrong here?
Edit:
This code is tested in g++ 4.6.1 and VC++ 2010 Express, both give the ambiguous error.

Guideline:
Do not overload:
template <typename T> void f(T&) {}
template <typename T> void f(T&&) {}
Reason:
There is a special template deduction rule for the pattern:
template <typename T> void f(T&&) {}
This rule exists in order to enable so called "perfect forwarding". It helps things like bind and make_shared forward their arguments perfectly, preserving both cv-qualifiers and "value category" (lvalue/rvalue-ness).
This special rule says that when f(T&&) is called with an lvalue parameter (e.g. int), that T gets deduced as an lvalue reference (e.g. int&) instead of int. And an rvalue reference to lvalue reference to int collapses down to just lvalue reference to int. I.e.
f(x)
calls
f<int&>(int& && x);
which simplifies to:
f<int&>(int& x);
Edit
This is not more or less specialized than f<int>(int&).
Thanks to Johannes Schaub for the correction (see comments).
Solution:
You can do whatever you want with the single function:
template <typename T> void f(T&&) {}
If T deduces as an lvalue reference, do whatever you wanted to do in your first overload, otherwise do whatever you wanted to do in your second overload:
template <class T> void f_imp(T&, std::true_type) {std::cout << "lvalue\n";}
template <class T> void f_imp(T&&, std::false_type) {std::cout << "rvalue\n";}
template <typename T> void f(T&& x)
{
f_imp(std::forward<T>(x), std::is_lvalue_reference<T>());
}
And use std::forward to perfectly forward x to the implementation-detail function.

Your interpretation of the standard appears to be correct.
template <typename T> void f(T&) {} // #1
template <typename T> void f(T&&) {} // #2
In #1, T is successfully deduced as int, and in #2, T is successfully deduced as int&, so partial ordering is performed to select the function to call. During partial ordering for the call f(x), the types of the first (only, in this case) argument will be ordered ([temp.deduct.partial]/3 bullet 1). During deduction in both directions, type P will be T, and type A will be a synthesized type representing T ([temp.deduct.partial]/5), so deduction succeeds in both directions.
As you observed, [temp.deduct.partial]/9 then applies, and says that #1's first argument is more specialized. Therefore, by [temp.deduct.partial]/10, #1 is selected as the most-specialized template and its specialization is the result of overload resolution.
You didn't mention which compiler you are using. I assume it's g++ -- this appears to be a bug in that compiler (I've tested versions between 4.4.3 and 4.7, and they all reject this code). clang accepts your code, and calls the f(T &) overload as you expected.

Related

Why are variadic templates different than non-variadic, for only one argument?

This code compiles just fine:
template <typename T1>
struct Struct {
};
struct ConvertsToStruct {
operator Struct<int>() const;
};
template <typename T>
void NonVariadicFunc(Struct<T>);
int main() {
NonVariadicFunc<int>(ConvertsToStruct{});
return 0;
}
But an attempt to make it a little more generic, by using variadic templates, fails to compile:
template <typename T1>
struct Struct {
};
struct ConvertsToStruct {
operator Struct<int>() const;
};
template <typename... T>
void VariadicFunc(Struct<T...>);
int main() {
VariadicFunc<int>(ConvertsToStruct{});
return 0;
}
What's going wrong? Why isn't my attempt to explicitly specify VariadicFunc's template type succeeding?
Godbolt link => https://godbolt.org/g/kq9d7L
There are 2 reasons to explain why this code can't compile.
The first is, the template parameter of a template function can be partially specified:
template<class U, class V> void foo(V v) {}
int main() {
foo<double>(12);
}
This code works, because you specify the first template parameter U and let the compiler determine the second parameter. For the same reason, your VariadicFunc<int>(ConvertsToStruct{}); also requires template argument deduction. Here is a similar example, it compiles:
template<class... U> void bar(U... u) {}
int main() {
bar<int>(12.0, 13.4f);
}
Now we know compiler needs to do deduction for your code, then comes the second part: compiler processes different stages in a fixed order:
cppreference
Template argument deduction takes place after the function template name lookup (which may involve argument-dependent lookup) and before template argument substitution (which may involve SFINAE) and overload resolution.
Implicit conversion takes place at overload resolution, after template argument deduction. Thus in your case, the existence of a user-defined conversion operator has no effect when compiler is doing template argument deduction. Obviously ConvertsToStruct itself cannot match anything, thus deduction failed and the code can't compile.
The problem is that with
VariadicFunc<int>(ConvertsToStruct{});
you fix only the first template parameter in the list T....
And the compiler doesn't know how to deduce the remaining.
Even weirder, I can take the address of the function, and then it works
It's because with (&VariadicFunc<int>) you ask for the pointer of the function (without asking the compiler to deduce the types from the argument) so the <int> part fix all template parameters.
When you pass the ConvertToStruct{} part
(&VariadicFunc<int>)(ConvertToStruct{});
the compiler know that T... is int and look if can obtain a Struct<int> from a ConvertToStruct and find the apposite conversion operator.

Overload resolution with template parameters

I am having trouble understanding why the following leads to an ambiguous call:
#include <iostream>
// generic version f(X, Y)
template <class X, class Y>
void f(X x, Y y) {
std::cout << "generic" << std::endl;
}
// overload version
template <class X>
void f(X x, typename X::type y) {
std::cout << "overload" << std::endl;
}
struct MyClass {
using type = int;
};
int main() {
f(MyClass(), int()); // Call to f is ambiguous
}
I would expect the overload version, which is more specialised in the second argument than the generic version, to be selected as the best candidate. I know that if I change the overload version to
template <class X>
void f(X x, int y) {
std::cout << "overload" << std::endl;
}
then the call is resolved just fine, which means it has to do with the fact that X::type is a template dependent name, but still cannot work out why it fails. Any help is much appreciated.
First, we pick the viable candidates. Those are:
void f(MyClass, int); // with X=MyClass, Y=int
void f(MyClass, typename MyClass::type); // with X=MyClass
Those candidates both take the same arguments, so have equivalent conversion sequences. So none of the tiebreakers based on those apply, so we fall back to the last possible tiebreaker in [over.match.best]:
Given these definitions, a viable function F1 is defined to be a better function than another viable function
F2 if for all arguments i, ICSi(F1) is not a worse conversion sequence than ICSi(F2), and then [...] F1 and F2 are function template specializations, and the function template for F1 is more specialized
than the template for F2 according to the partial ordering rules described in 14.5.6.2.
So we try to order the two function templates based on the partial ordering rules, which involve synthesizing a unique type for each template parameter and attempting to perform template deduction against each over overload. But with a key additional relevant rule from [temp.deduct.partial]:
Each type nominated above from the parameter template and the corresponding type from the argument
template are used as the types of P and A. If a particular P contains no template-parameters that participate
in template argument deduction, that P is not used to determine the ordering.
So what does this mean. First, let's try to deduce the generic version from the overload. We pick synthetic types UniqueX (for X) and UniqueX_type (for typename X::type) and see if we can invoke the generic function. This succeeds (with X=UniqueX and Y=typename X::type).
Let's try the inverse. We pick a UniqueX (for X) and a UniqueY (for Y) and try to perform template deduction. For the first P/A pair, this trivially succeeds. But for the second argument, X is a non-deduced context, which you would think would mean that template deduction fails. BUT as per the bolded part of the quote, we just skip this P/A pair for the purposes of ordering. So, since the first P/A pair succeeded, we consider the entire deduction process to have succeeded.
Since template deduction succeeds in both directions, we cannot pick one function or the other as being more specialized. Since there are no further tiebreakers, there is no single best viable candidate, so the call is ambiguous.
When the second overload is changed to:
template <class X> void f(X, int);
the part of the process that changes is that deduction now fails in one direction. We can deduce X=UniqueX but the second pair has a parameter of type int and an argument of type UniqueY, which will not work, so this direction fails. In the reverse direction, we can deduce X=UniqueX and Y=int. That makes this overload more specialized that the generic overload, so it would be preferred by the last tiebreaker I originally mentioned.
As an addendum, note that partial ordering of templates is complicated. Consider:
template <class T> struct identity { using type = T; };
template <class T> void foo(T ); // #1
template <class T> void foo(typename identity<T>::type ); // #2
template <class T> void bar(T, T); // #3
template <class T> void bar(T, typename identity<T>::type ); // #4
foo(0); // calls #1, #2 isn't even viable
foo<int>(0); // calls #2
bar(0,0); // calls #3! we fail to deduce 3 from 4, but we succeed
// in deducing 4 from 3 because we ignore the second P/A pair!

Implications of conversion function template argument deduction in C++

I'm having trouble understanding the implications of the conversion function template argument deduction rules in the C++ standard. The standard states that ([temp.deduct.conv] clause 1, §14.8.2.3.1 in N4594):
Template argument deduction is done by comparing the return type of the conversion function template (call it P) with the type that is required as the result of the conversion (call it A; see 8.5, 13.3.1.5, and 13.3.1.6 for the determination of that type) as described in 14.8.2.5.
where 14.8.2.5 ([temp.deduct.type]) is the section that describes general template argument deduction (though the most common case, function call template argument deduction [temp.deduct.call], no longer seems to point there; did it ever?). The next clause is what confuses me, though (clause 2):
If P is a reference type, the type referred to by P is used in place of P for type deduction and for any further references to or transformations of P in the remainder of this section.
To me, this seems to imply that template <class T> operator T() and template <class T> operator T&() are the same (and specifying both would result in an ambiguity). But that isn't the case in any compiler I've used! For instance:
struct any1 { template <typename T> operator T() { } };
struct any2 { template <typename T> operator T&() { } };
void f1(int) { }
void f2(int&) { }
void f3(int const&) { }
int main() {
f1(any1());
// f2(any1()); compile time error
f3(any1());
f1(any2());
f2(any2());
f3(any2());
}
Live Demo
But if references are ignored, any1 and any2 should have the same behavior, right? Clearly they don't, since f2(any1()) doesn't compile with either gcc or clang, while f2(any2()) compiles fine with both.
The next clause (clause 3, particularly 3.3) confuses things even further:
If A is not a reference type: [...] If P is a cv-qualified type, the top level cv-qualifiers of P’s type are ignored for type deduction.
This, along with clause 2 about the removal of references, would seem to imply that the following code should not compile because of an ambiguity:
struct any3 {
template <typename T> operator T&() { }
template <typename T> operator T const&() { }
};
void f1(int) { }
int main() {
f1(any3());
}
Live Demo
And yet this works fine with both gcc and clang.
What am I missing?
Edit
I should clarify that the way the clang and gcc compilers handle this is exactly what I would expect from a general (relatively advanced) understanding of C++. Some commenters have asked for clarification on what my confusion is (and, implicitly, why I should care). My confusion here is entirely related to trying to understand the implications of the standard. I need a clear understanding of this because I am submitting a paper with code that relies heavily on this working and on my use of it being standards-compliant.
The key point you're missing is that overload resolution still has to happen. Template deduction isn't the end of the story. Addressing both of your examples separately:
To me, this seems to imply that template <class T> operator T() and template <class T> operator T&() are the same (and specifying both would result in an ambiguity). But that isn't the case in any compiler I've used!
The text you cite indicates that deduction of T is the same for both conversion operators, this is true. But the operators themselves are not the same. You have to additionally consider the rules for binding to references, which are enumerated in [dcl.init.ref]. The section is too long to concisely copy, but the reason that this is an error
f2(any1()); // error
is the same reason that f2(1) is an error: you can't bind an lvalue reference to non-const to an rvalue. As a result, even having both operators isn't in of itself ambiguous:
struct X {
template <class T> operator T(); // #1
template <class T> operator T&(); // #2
};
f1(X{}); // error: ambiguous
f2(X{}); // ok! #1 is not viable, calls #2
f3(X{}); // ok! #2 is preferred (per [dcl.init.ref]/5.1.2)
And yet this works fine with both gcc and clang.
struct any3 {
template <typename T> operator T&(); // #3
template <typename T> operator T const&() // #4
};
void f1(int) { }
int main() {
f1(any3());
}
This is an interesting scenario as far as compilers go, because gcc has a bug here. Both candidates should be valid (gcc doesn't consider #4 valid due to 61663). None of the tiebreakers apply on determining best viable candidate, so in this case we have to fall back to [temp.deduct.partial] to determine which candidate is more specializated... which, in this case, is #4.
Template argument deduction for a function template is just one step in the complex process of overload resolution.
§13.3.1 Candidate functions and argument lists
...
7 In each case where a candidate is a function template, candidate function
template specializations are generated using template argument deduction
(14.8.3, 14.8.2).
Template argument deduction is performed for a given function template as if no other function template exists. Reread the section §14.8.2.3 with that in mind, and you will realize that your questions belong to a different part of the standard.
After template argument deduction is performed for all candidate template functions, the best viable function must be selected according to the rules of §13.3.3. If by this time two or more function template specializations are present in the candidate function list, then the best viable function selection process involves partial ordering rules described in §14.5.6.2 (I think it's this section that contains answers to you questions).
Type deduction is a separate step from overload resolution and semantic checking.
struct any1 { template <typename T> operator T() { } };
struct any2 { template <typename T> operator T&() { } };
void f1(int) { }
void f2(int&) { }
void f3(int const&) { }
int main() {
f1(any1());
// f2(any1()); compile time error
f3(any1());
f1(any2());
f2(any2());
f3(any2());
}
Here f2(any1()) and f2(any2()) do behave identically for type deduction. Both deduce T=int. But then that T is substituted into the original declaration to get member specializations any1::operator int() and any2::operator int&(). f2(any1().operator int()) is a semantic error because it attempts to bind a non-const lvalue reference function parameter to an rvalue expression. This makes operator int() a non-viable function; if any1 had other conversion functions, they could be selected by overload resolution.
struct any3 {
template <typename T> operator T&() { }
template <typename T> operator T const&() { }
};
void f1(int) { }
int main() {
f1(any3());
}
Here again, the two template conversion functions do behave identically for type deduction. Both deduce T=int. Then that deduction is substituted into the original declarations to get operator int&() and operator int const&(). Then overload resolution compares those two. By my reading of Clause 13, they are ambiguous, but gcc chooses operator int&() and clang chooses operator int const&()...

SFINAE and the address of an overloaded function

I'm experimenting with resolving the address of an overloaded function (bar) in the context of another function's parameter (foo1/foo2).
struct Baz {};
int bar() { return 0; }
float bar(int) { return 0.0f; }
void bar(Baz *) {}
void foo1(void (&)(Baz *)) {}
template <class T, class D>
auto foo2(D *d) -> void_t<decltype(d(std::declval<T*>()))> {}
int main() {
foo1(bar); // Works
foo2<Baz>(bar); // Fails
}
There's no trouble with foo1, which specifies bar's type explicitly.
However, foo2, which disable itself via SFINAE for all but one version of bar, fails to compile with the following message :
main.cpp:19:5: fatal error: no matching function for call to 'foo2'
foo2<Baz>(bar); // Fails
^~~~~~~~~
main.cpp:15:6: note: candidate template ignored: couldn't infer template argument 'D'
auto foo2(D *d) -> void_t<decltype(d(std::declval<T*>()))> {}
^
1 error generated.
It is my understanding that C++ cannot resolve the overloaded function's address and perform template argument deduction at the same time.
Is that the cause ? Is there a way to make foo2<Baz>(bar); (or something similar) compile ?
As mentioned in the comments, [14.8.2.1/6] (working draft, deducing template arguments from a function call) rules in this case (emphasis mine):
When P is a function type, function pointer type, or pointer to member function type:
If the argument is an overload set containing one or more function templates, the parameter is treated as a non-deduced context.
If the argument is an overload set (not containing function templates), trial argument deduction is attempted using each of the members of the set. If deduction succeeds for only one of the overload set members, that member is used as the argument value for the deduction. If deduction succeeds for more than one member of the overload set the parameter is treated as a non-deduced context.
SFINAE takes its part to the game once the deduction is over, so it doesn't help to work around the standard's rules.
For further details, you can see the examples at the end of the bullet linked above.
About your last question:
Is there a way to make foo2<Baz>(bar); (or something similar) compile ?
Two possible alternatives:
If you don't want to modify the definition of foo2, you can invoke it as:
foo2<Baz>(static_cast<void(*)(Baz *)>(bar));
This way you explicitly pick a function out of the overload set.
If modifying foo2 is allowed, you can rewrite it as:
template <class T, class R>
auto foo2(R(*d)(T*)) {}
It's more or less what you had before, no decltype in this case and a return type you can freely ignore.
Actually you don't need to use any SFINAE'd function to do that, deduction is enough.
In this case foo2<Baz>(bar); is correctly resolved.
Some kind of the general answer is here: Expression SFINAE to overload on type of passed function pointer
For the practical case, there's no need to use type traits or decltype() - the good old overload resolution will select the most appropriate function for you and break it into 'arguments' and 'return type'. Just enumerate all possible calling conventions
// Common functions
template <class T, typename R> void foo2(R(*)(T*)) {}
// Different calling conventions
#ifdef _W64
template <class T, typename R> void foo2(R(__vectorcall *)(T*)) {}
#else
template <class T, typename R> void foo2(R(__stdcall *)(T*)) {}
#endif
// Lambdas
template <class T, class D>
auto foo2(const D &d) -> void_t<decltype(d(std::declval<T*>()))> {}
It could be useful to wrap them in a templated structure
template<typename... T>
struct Foo2 {
// Common functions
template <typename R> static void foo2(R(*)(T*...)) {}
...
};
Zoo2<Baz>::foo2(bar);
Although, it will require more code for member functions as they have modifiers (const, volatile, &&)

Overload resolution and universal reference parameters

The following code works and the overloads are found as expected:
struct HasBuzz
{
void buzz() const {}
};
struct NoBuzz {};
template <typename T>
void foo(T const& t)
{
t.buzz();
}
void foo(NoBuzz const&){}
int main()
{
foo(HasBuzz{});
foo(NoBuzz{});
}
However, if I replace the first overload with a "universal reference" version then it no longer works. The correct overload is not found for NoBuzz.
struct HasBuzz
{
void buzz() const {}
};
struct NoBuzz {};
template <typename T>
void foo(T&& t)
{
t.buzz();
}
void foo(NoBuzz const&){}
int main()
{
foo(HasBuzz{});
foo(NoBuzz{}); // error: NoBuzz has no member function buzz
}
What can I do to make it work?
Simple solution
Add an overload that is callable with an rvalue of type NoBuzz.
void foo(NoBuzz const&){ };
void foo(NoBuzz&&) { }; // overload for rvalues
Note: Depending on your actual use case this might not be enough, because if you pass a non-const lvalue type NoBuzz to foo you'd still instantiate the template, since the two NoBuzz overloads doesn't match. At the end of this post is a more complex, but certainly cleaner, solution.
Explanation
template<class T>
void foo (T&&); // (A)
void foo (NoBuzz const&); // (B)
The problem with your snippet is that your template (A) can be instantiated in such a way that it's a better match than your overload (B).
When the compiler sees that you are trying to call a function named foo with an argument which is an rvalue of type NoBuzz, it will look for all functions named foo taking one argument where a NoBuzz would fit.
Let's say it starts of with your template (A), here it sees that T&& is deducable to any reference type (both lvalue, and rvalue), since we are passing an rvalue T = NoBuzz.
With T = NoBuzz the instantiated template would be semantically equivalent to:
void foo (NoBuzz&&); // (C), instantiated overload of template (A)
It will then continue to your overload (B). This overload accepts a const lvalue reference, which can bind to both lvalues and rvalues; but our previous template instantiation (C) can only bind to rvalues.
Since (C) is a better match than (B), binding rvalues to T&& is prefered over U const&, that overload is selected and you get the behavior you describe in your post.
Advanced solution
We can use a technique called SFINAE to conditionally make it impossible to call the template if the type passed doesn't implement .buzz ().
template <typename T>
auto foo(T&& t) -> decltype (t.buzz ())
{
return t.buzz();
}
The above solution uses a lot of new features of C++11, detailed information is available here:
wikipedia.org - C++11 - auto
wikipedia.org - decltype
Conditional overloading with trailing-return-type possible?
refp's answer explains the behavior you're seeing, and offers a possible solution. Another option is to ensure the foo function template does not make it into the candidate set for overload resolution unless T has a member function named buzz().
template <typename T>
auto foo(T&& t)
-> decltype((void)(t.buzz()), void())
{
t.buzz();
}
After making this change the foo(NoBuzz const&) overload will be selected when you pass it an instance of NoBuzz. Live demo
A detailed explanation of what's going on in the decltype expression in the trailing return type can be found here. The only thing I've done differently here is instead of using three subexpressions, with the middle one being void() to prevent a user defined operator, from being selected, I've cast the result of the first expression to void; the intent and result are identical in both cases.