Rule for which function overload to specialize - c++

Consider the code:
#include <iostream>
template <typename T>
void f(T)
{
std::cout << "Version 1" << std::endl;
}
template <typename T>
void f(T *)
{
std::cout << "Version 2" << std::endl;
}
template <>
void f<>(int *)
{
std::cout << "Version 3" << std::endl;
}
int main()
{
int *p = nullptr;
f(p);
return 0;
}
This code will output Version 3. What is happening is that function overloading rules look at the first two versions of void f (the third version is a specialization and does not participate in the overload), and decides that the second version is the better version. Once that decision is made, we then see if any specializations exist for the second version. There is, and we use it.
My question, then, is: How did the compiler know that my explicit specialization was a specialization of the second overload and not the first one? I have not provided it with a template parameter for it to make that choice. Is it simply the case that deciding which function to specialize follows a similar/the same rule as deciding which overload to call (if it were calling the function)? That would make some sense...

There is that example in template_argument_deduction#Explicit_instantiation
Template argument deduction is used in explicit instantiations, explicit specializations, and those friend declarations where the declarator-id happens to refer to a specialization of a function template (for example, friend ostream& operator<< <> (...)), if not all template arguments are explicitly specified or defaulted, template argument deduction is used to determine which template's specialization is referred to.
P is the type of the function template that is being considered as a potential match, and A is the function type from the declaration. If there are no matches or more than one match (after partial ordering), the function declaration is ill-formed:
template<class X> void f(X a); // 1st template f
template<class X> void f(X* a); // 2nd template f
template<> void f<>(int* a) { } // explicit specialization of f
// P1 = void(X), A1 = void(int*): deduced X = int*, f<int*>(int*)
// P2 = void(X*), A2 = void(int*): deduced X = int, f<int>(int*)
// f<int*>(int*) and f<int>(int*) are then submitted to partial ordering
// which selects f<int>(int*) as the more specialized template

Related

overloaded templates resolution

// g++(5.4)
void func(int * const &) {}
void func(int *) {}
template <typename T> void tfunc(const T &) {}
template <typename T> void tfunc(T *) {}
int main()
{
int a = 0;
func(&a); // ambiguous
tfunc(&a); // unambiguous
return 0;
}
According to my another test, tfunc(&a) instantiates the first template to void tfunc(int * const &) which has the same parameter type as the first nontemplate.
So, why is the first call ambiguous but the second not?
Given two function templates that are otherwise equally as good, overload resolution will select the more specialized function template, using a procedure commonly known as partial ordering. The exact rules are pretty complicated, but essentially it tries to determine if the set of arguments template A can be called with is a (proper) subset of the set of arguments template B can be called with. If so, then A is more specialized than B, and overload resolution will prefer A.
Thus, in your case, tfunc(const T&) can be called with ~everything; tfunc(T*) can only be called with pointers. The latter is more specialized, and is therefore selected.
If you are interested in the standardese and detailed rules, see [temp.func.order] and [temp.deduct.partial].
There are some special rules in overload resolution for template functions, one of them is :
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.
See this question about how to determine which function template is more specialized.
Here, as the second template function is more specialized, there is no ambiguation.
#include <iostream>
void func(int * const &) {}
void func(int *) {}
template <typename T> void tfunc(const T &) {std::cout << "#1\n";}
template <typename T>void tfunc(T *) {std::cout << "#2\n";}
int main()
{
int a = 0;
//func(&a); // ambiguous
tfunc(&a); // unambiguous
return 0;
}
// output: #2
Edit: Though a test in https://ideone.com/C9rF8b , we can see that the second template is chosen, not the first one as stated in the question.
Because a const pointer and a non-const pointer (i.e. T * const and T *) makes no difference if they appear in a function's parameters, and so does passing by value (by copy) and passing by const reference. That's the reason why f(&a) is ambiguous.
For the second one, since &a is resolved to int *, the second template matches better because it's more specialized (it can't accept non-pointer arguments). The first template is more general so it's not used.
If you change the first template function to this it will also be ambiguous:
template <typename T>
void tfunc(T * const &) {}

C++ function template specialization and overloading

Considering this code:
template <class T>
void f(T p) { //(1)
cout << "Second" << endl;
}
template <>
void f(int *p) { //(2)
cout << "Third" << endl;
}
template <class T>
void f(T* p) { //(3)
cout << "First" << endl;
}
A call such as int *p; f(p); will output First.
If the order of the declarations is changed, like this:
template <class T>
void f(T* p) { //(3)
cout << "First" << endl;
}
template <class T>
void f(T p) { //(1)
cout << "Second" << endl;
}
template <>
void f(int *p) { //(2)
cout << "Third" << endl;
}
the same call (int *p; f(p);) will output Third.
I read about the way in which function template overload resolution takes places: first the resolution considers only non-template functions and the underlying base templates. After the "most specialized" one is chosen, if it is a template function and it has a specialization for the parameters which were deduced (or explicitly specified), that specialization is called.
Now my question is: how it is decided for which underlying base template a function is a specialization? In my example, for which function template overload ( (1) or (3) ) is (2) a specialization?
My guess is that when a specialization is declared, the templates already declared are considered, and from those the most "specialized" (whose parameters are "closest" to this specialization) is chosen. Is this correct? Also, could you point me to where this is specified in the standard?
It prints "First" because the order of declaration affects which template you in fact specialize.
Your example has two function templates, which overload the same name. In the first case, you specialize void f(T p), because it's the only template seen so far.
In the second case, it's void f(T* p) that's specialized. So yes, your guess is correct. The specifics are at [temp.deduct.decl/1]:
In a declaration whose declarator-id refers to a specialization of a
function template, template argument deduction is performed to
identify the specialization to which the declaration refers.
Specifically, this is done for explicit instantiations, explicit
specializations, and certain friend declarations. [...]
And that includes the partial ordering of the function templates. However, partial ordering only applies to the available function template declarations at the point you introduce your specialization.
And the standard warns at [temp.expl.spec/7]:
The placement of explicit specialization declarations for function templates, [...] , can affect whether a program is well-formed
according to the relative positioning of the explicit specialization
declarations and their points of instantiation in the translation unit
as specified above and below. When writing a specialization, be
careful about its location; or to make it compile will be such a trial
as to kindle its self-immolation.

Overload resolution and explicit template arguments

The following code prints "func 2".
Why does the compiler treat the second template as a better match, in presence of explicit (not deduced) template arguments? Why is there no ambiguity?
I'd appreciate quotations from the C++ standard.
#include <iostream>
template<class T>
struct identity
{
typedef T type;
};
template<class T>
void func(T)
{
std::cout << "func 1\n";
}
template<class T>
void func(typename identity<T>::type)
{
std::cout << "func 2\n";
}
int main()
{
func<int>(1);
}
Both candidates are viable and take identical arguments, so the overload resolution process falls back to the last tiebreaker: partial ordering of function templates [temp.func.order].
The rule is that we synthesize a new type for each template type parameter and attempt to perform deduction on each other overload. For 1, we synthesize a type Unique1, which fails deduction on 2 because T is a non-deduced context. For 2, we synthesize a type Unique2, which succeeds deducing T = typename identity<Unique2>::type. Since deduction succeeds in one direction and not the other, that makes 2 more specialized than 1, hence it's preferred.
Note that template partial ordering rules are somewhat incomplete in the standard. If you simply add another argument of type T, the preference flips.

When are two function templates considered as partially ordered and when are ambiguous?

I'm completely confused after reading the question How to make these std::function parameters unambiguous?, so far I'd thought I understood what partial ordering of function templates is, but after reading that question I wrote down three examples to check the compiler's behavior, and the results received are hard for me to understand.
Example #1
template <class T>
void foo(T) {}
template <class T>
void foo(T&) {}
int main()
{
int i;
foo<int>(i); // error: call is ambiguous!
}
Question: Both functions are viable, that's obvious, but isn't the one taking T& more specialized than T? Instead, the compiler raises ambiguous call error.
Example #2
#include <iostream>
template <class T>
struct X {};
template <>
struct X<int>
{
X() {}
X(X<int&> const&) {} // X<int> is constructible from X<int&>
// note: this is not a copy constructor!
};
template <>
struct X<int&>
{
X() {}
X(X<int> const&) {} // X<int&> is constructible from X<int>
// note: this is not a copy constructor!
};
template <class T>
void bar(X<T>) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
template <class T>
void bar(X<T&>) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
int main()
{
bar<int>(X<int>()); // calls void bar(X<T>) [with T = int]
bar<int>(X<int&>()); // calls void bar(X<T&>) [with T = int]
}
Question: If the T& and T are ambiguous in Example #1, then why here none call is ambiguous? X<int> is constructible from X<int&>, as well as X<int&> is constructible from X<int> thanks to provided constructors. Is it because compiler generated X<int>::X(X<int> const&) copy-constructor is a better conversion sequence than X<int>::X(X<int&> const&), (if so, what makes it better, note that arguments are passed by value), and so the ordering of specializations does not matter at all?
Example #3
#include <iostream>
// note: a new type used in constructors!
template <class U>
struct F {};
template <class T>
struct X
{
X() {}
template <class U>
X(F<U> const&) {} // X<T> is constructible from any F<U>
// note: it takes F type, not X!
};
template <class T>
void qux(X<T>) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
template <class T>
void qux(X<T&>) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
int main()
{
qux<int>(F<int>()); // calls void qux(X<T&>) [with T = int]
qux<int>(F<int&>()); // calls void qux(X<T&>) [with T = int]
}
Question: Now this is similar scenario to "matching lambda [](int){} against std::function<void(int&)> and std::function<void(int)>" from question linked. Why in both calls the more specialized function template is picked? Is it because the conversion sequence is the same, so partial ordering starts to matter?
All tests done on GCC 4.9.0 with -std=c++11 and no extra flags.
Overload resolution tries to find the best function like this:
(1) [over.match.best]/1:
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 — for some argument j, ICSj(F1) is a better conversion
sequence than ICSj(F2), or, if not that, — the context is an
initialization by user-defined conversion (see 8.5, 13.3.1.5, and
13.3.1.6) and the standard conversion sequence from the return type of F1 to the destination type (i.e., the type of the entity being
initialized) is a better conversion sequence than the standard
conversion sequence from the return type of F2 to the destination
type. [ Example:
struct A {
A();
operator int();
operator double();
} a;
int i = a; // a.operator int() followed by no conversion is better
// than `a.operator double()`
// followed by a conversion to `int`
float x = a; // ambiguous: both possibilities require conversions,
// and neither is better than the other
— end example ] or, if not that, — F1 is a non-template
function and F2 is a function template specialization, or, if not
that, — 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.
Case 1:
but isn't the one taking T& more specialized than T?
According to overload resolution, no conversion is better (both are identity conversions, which are exact matches), and since no other bullet in (1) applies, partial ordering is done. [temp.deduct.partial]/5 says that references are replaced by the type they refer to for purposes of partial ordering:
Before the partial ordering is done, certain transformations are
performed on the types used for partial ordering: — If P is a
reference type, P is replaced by the type referred to. — If A is a
reference type, A is replaced by the type referred to.
Since the parameters of the parameter templates are completely identical it is not hard to see that the deductions against each other are successful both ways -- so neither template is more specialized than the other.
Case 2:
Partial ordering isn't needed here. The user-defined-conversion from X<int> to X<int&> has a worse rank than converting X<int> to X<int> -- The latter is given Exact Match rank by [over.ics.user]/4:
A conversion of an expression of class type to the same class type is
given Exact Match rank, […]
Thus it's obviously a better conversion than X<int> to X<int&>, which has Conversion rank. Same goes vice versa, for X<int&> to X<int>.
Case 3:
The third case is similar to the first. X<int> and X<int&> both have a constructor template that can take an arbitrary specialization of F. (1) tells us that since none of the conversion sequences is better than the other in any way (in fact, they are completely identical), the more specialized template is chosen.
template <class T> void bar(X<T>); // #1
template <class T> void bar(X<T&>); // #2
// Call:
bar<int>( F<int>() );
Going back to [temp.deduct.partial], type deduction is performed. A unique type, call it Unique, is synthesized for the template parameter of each argument template. The following procedures with corresponding results are carried out - note that the steps are exactly the same when calling with F<int> as with F<int&> (and any other specialization of F):
template #1 as the parameter template and template #2 as the argument template, X<Unique&> is deduced against X<T>, yielding T=Unique&. On the other hand,
template #2 as the parameter template against template #1 as the argument template, X<Unique> is deduced against X<T&>, which results in a deduction failure.
As we can see template #2 is more specialized. When used as an argument template in step 1, deduction succeeded, whereas for template #1 as the argument template in step 2, the deduction failed. Therefore the second, more specialized function templates' specialization is called.
Example 1 :
The compiler cannot know if you want to pass a by reference or by value. If you specialize your template with a T * he will know easily because the function call syntax will be different foo(&a).
Example 2 :
Here you tell the compiler that the second overload of qux takes a X<T &> so he knows that you want to construct this object with an T &. There is no ambiguity. But if you do this :
template <class T>
void qux(X<T>) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
template <class T>
void qux(X<T> &) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
You will end up with the same problem
Example 3:
Same problem.
I don't know if it's very clear so if someone could improve my answer, that could be useful to the author

Why SFINAE doesn't work in right side in default function arguments?

I have this code:
struct My
{
typedef int foo;
};
struct My2
{
};
template <typename T>
void Bar(const T&, int z = typename T::foo())
{
std::cout << "My" << std::endl;
}
void Bar(...)
{
std::cout << "..." << std::endl;
}
int main()
{
My my;
Bar(my); // OK
My2 my2;
Bar(my2); // Compile error: no type named ‘foo’ in ‘struct My2’
return 0;
}
I suppose, that if some class T doesn't have typedef foo inside, compiler should exclude first overload and choose overload with ellipsis. But I check this code on MSVC, gcc and clang and I get compile error on those compilers. Why SFINAE doesn't work in this case?
The type of z is not subject to template substitution, it is always int. This means there is no opportunity for SFINAE, and you instead get a compiler error when attempting to resolve T::foo for the default value. Default arguments do not participate in overload resolution, instead being instantiated only when missing from the function call. Section 14.7.1 (paragraphs 13/14) of the standard describes this behaviour, but does not give justification for the lack of SFINAE here.
SFINAE can be allowed to happen by making the type of z a template parameter, as below:
(live example: http://ideone.com/JynMye)
#include <iostream>
struct My
{
typedef int foo;
};
struct My2
{
};
template<typename T, typename I=typename T::foo> void Bar(const T&, I z = I())
{
std::cout << "My\n";
}
void Bar(...)
{
std::cout << "...\n";
}
int main()
{
My my;
Bar(my); // OK
My2 my2;
Bar(my2); // Also OK
return 0;
}
This will use the "My" version for the first call, and the "..." version for the second call. The output is
My
...
However, if void Bar(...) was a template, for whatever reason, the "My" version will never get a chance:
(live example: http://ideone.com/xBQiIh)
#include <iostream>
struct My
{
typedef int foo;
};
struct My2
{
};
template<typename T, typename I=typename T::foo> void Bar(const T&, I z = I())
{
std::cout << "My\n";
}
template<typename T> void Bar(T&)
{
std::cout << "...\n";
}
int main()
{
My my;
Bar(my); // OK
My2 my2;
Bar(my2); // Also OK
return 0;
}
Here, the "..." version is called in both cases. The output is:
...
...
One solution is to use class template (partial) specialisation; provide the "..." version as the base, with the type of the second parameter defaulted to int, and the "My" version as a specialisation where the second parameter is typename T::foo. In conjunction with a plain template function to deduce T and dispatch to the appropriate class' member function, this produces the desired effect:
(live example: http://ideone.com/FanLPc)
#include <iostream>
struct My
{
typedef int foo;
};
struct My2
{
};
template<typename T, typename I=int> struct call_traits {
static void Bar(...)
{
std::cout << "...\n";
}
};
template<typename T> struct call_traits<T, typename T::foo> {
static void Bar(const T&, int z=typename T::foo())
{
std::cout << "My\n";
}
};
template<typename T> void Bar(const T& t)
{
call_traits<T>::Bar(t);
}
int main()
{
My my;
Bar(my); // OK
My2 my2;
Bar(my2); // Still OK
return 0;
}
Here, the output is:
My
...
The type z is an int, is not being deduced by the compiler, no room for SFINAE to take place. The value being used to initialise z is based on the default of T::foo, which doesn't exist; hence the error.
If the type for z is elevated to the template itself, substitution can now fail, and SFINAE kicks in.
#include <iostream>
struct My
{
typedef int foo;
};
struct My2
{
};
template <typename T, typename I = typename T::foo>
void Bar(const T&, I z = I())
{
(void)z; // silence any warnings on unused
std::cout << "My" << std::endl;
}
void Bar(...)
{
std::cout << "..." << std::endl;
}
int main()
{
My my;
Bar(my);
My2 my2;
Bar(my2); // Compiles
return 0;
}
Live sample
In order for a function template to be part of the overloaded list of candidate functions, the template argument deduction must succeed. If it fails, then the candidate is removed from the list. Hence, if no deduction failure occurs, it is added to the candidate list (but this does not preclude further errors if it is finally selected).
14.8.3/1 Overload resolution
A function template can be overloaded either by (non-template) functions of its name or by (other) function templates of the same name. When a call to that name is written (explicitly, or implicitly using the operator notation), template argument deduction (14.8.2) and checking of any explicit template arguments (14.3) are performed for each function template to find the template argument values (if any) that can be used with that function template to instantiate a function template specialization that can be invoked with the call arguments. For each function template, if the argument deduction and checking succeeds, the template arguments (deduced and/or explicit) are used to synthesize the declaration of a single function template specialization which is added to the candidate functions set to be used in overload resolution. If, for a given function template, argument deduction fails, no such function is added to the set of candidate functions for that template. The complete set of candidate functions includes all the synthesized declarations and all of the non-template overloaded functions of the same name. The synthesized declarations are treated like any other functions in the remainder of overload resolution, except as explicitly noted in 13.3.3.
Template argument deduction is performed on the function type and its template arguments themselves.
14.8.2/8 Template argument deduction
If a substitution results in an invalid type or expression, type deduction fails. An invalid type or expression is one that would be ill-formed, with a diagnostic required, if written using the substituted arguments. [ Note: If no diagnostic is required, the program is still ill-formed. Access checking is done as part of the substitution process. —end note ] Only invalid types and expressions in the immediate context of the function type and its template parameter types can result in a deduction failure.
From the OP, the function Bar<T> is added to the candidate list since it can be deduced what the type for T is. It is instantiated and the default arguments are checked, and hence it fails.
14.7.1/13 Implicit instantiation
If a function template f is called in a way that requires a default argument to be used, the dependent names are looked up, the semantics constraints are checked, and the instantiation of any template used in the default argument is done as if the default argument had been an initializer used in a function template specialization with the same scope, the same template parameters and the same access as that of the function template f used at that point. This analysis is called default argument instantiation. The instantiated default argument is then used as the argument of f.
Quotes taken from draft n3797
One more C++03 compatible option for you. Because in answers above default argument was used in template function and it is not permitted in standard.
#include <iostream>
struct TypeWithFoo{
typedef int Foo;
};
template<typename T, bool>
struct onFooAction;
template<typename T>
struct onFooAction<T, false>{
void operator ()(const T &t){
std::cout << "No foo :(\n";
}
};
template<typename T>
struct onFooAction<T, true>{
void operator ()(const T &t){
std::cout << "Foo =)\n";
}
};
template<typename T>
struct hasFoo{
typedef char yes[1];
typedef char no[2];
template<typename C>
static yes& testForFoo(typename C::Foo*);
template<typename>
static no& testForFoo(...);
static const bool value = sizeof(testForFoo<T>(0)) == sizeof(yes);
};
template<typename T>
void bar(const T &t){
onFooAction<T, hasFoo<T>::value>()(t);
}
int main(){
bar(10);
bar(TypeWithFoo());
}