I had created a Template Specialized function and a non template function with the same arguments. Since effectively both are same functions, I was not sure how C++ compiler would run it as now it has two same functions, one is a template specialized the other is a non template one. I was expecting this would result in a compiler error as compiler would find two functions with the same parameters and return type (In this case void foo(string) ). But looks like the non template version is the one that executes when this is called.
So is there a precedence when this is done?
Kindly let me know if I have misunderstood.
Code: This prints 'String Non-Template'
#include <iostream>
#include <string>
using namespace std;
template<typename T>
void foo(T input)
{
cout <<"Generic Template"<<endl;
}
template<>
void foo<string>(string input)
{
cout <<"String Template"<<endl;
}
void foo(string input)
{
cout <<"String Non-Template"<<endl;
}
int main() {
string input = "abc";
foo(input);
return 0;
}
A regular function is always preferred over a function template, even a specialization of the function template.
From the C++ Standard:
13.3.3 Best viable function [over.match.best]
1 Define ICSi(F) as follows:
...
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 is a non-template function and F2 is a function template specialization, or, if not that,
Related
Consider the following code:
#include <iostream>
#include <type_traits>
template <typename T>
class A
{
public:
// Allow func to be called if T is the const version of T2
// e.g., T is 'int const' and T2 is 'int'
template <typename T2,
typename = typename std::enable_if<
std::is_same<T, T2 const>::value>::type>
void func(A<T2> const &)
{
std::cout << "Conversion" << std::endl;
}
// Allow func to be called for same version of T
void func(A const &)
{
std::cout << "No conversion" << std::endl;
}
};
int main()
{
A<int const> a;
a.func(A<int const>{});
return 0;
}
This code, when compiled with GCC-8.3 compiles and produces the output No conversion - it selected the version of func that does not use std::enable_if. However, if I comment out the second version of func, it will still compile and now produce the output Conversion. In other words, both versions of func within A are usable for this method. Given that both overloads are viable, what specific rule is the compiler using to select func(A const &) over the other version (func(A<T2> const &))?
The rule is that if a non function template and a function template specialization have the same signature, then the non function template is chosen over the template specialization. This can be found in [over.match.best]/2
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 is not a function template specialization and F2 is a function template specialization [...]
You can read about overload resolution here. In particular
If any candidate is a function template, its specializations are generated using template argument deduction, and such specializations are treated just like non-template functions except where specified otherwise in the tie-breaker rules.
And then
Best viable function
For each pair of viable function F1 and F2, the implicit conversion sequences from the i-th argument to i-th parameter are ranked to determine which one is better [...]
F1 is determined to be a better function than F2 if implicit conversions for all arguments of F1 are not worse than the implicit conversions for all arguments of F2, and
[...]
4) [...] F1 is a non-template function while F2 is a template specialization
Basically the same rules apply in this simpler example:
#include<iostream>
template <typename T>
void foo(T i) { std::cout << "template" ; }
void foo(int i) { std::cout << "non template"; }
int main() {
foo(1); // non template
}
I have two templated functions with the same name (foo). Their signatures differ only in the type of the second parameter, which is dependent on the template parameter T. What has surprised me is that I can use this to overload depending on whether T::A or T::B is an existent type. Is this something which is specially provided for in the standard (if so, a reference would be much appreciated), or am I just being dense in not recognising this as basic overload resolution?
#include <iostream>
using namespace std;
template<typename T>
void foo(T t, typename T::A* a = 0) {
cout << "Had an A" << endl;
}
template<typename T>
void foo(T t, typename T::B* b = 0) {
cout << "Had a B" << endl;
}
struct HasAnAType {
typedef int A;
};
struct HasABType {
typedef int B;
};
struct HasAAndBTypes {
typedef int A;
typedef int B;
};
int main() {
HasAnAType a;
HasABType b;
HasAAndBTypes ab;
foo(a); // prints "Had an A"
foo(b); // prints "Had a B"
foo(ab); // won't compile: 'ambiguous call to overloaded function'
}
For background, I discovered this was possible when looking into the implementation of std::enable_shared_from_this, which relies on this type of overloading.
Thanks to SFINAE, the overload void foo(T t, typename T::B* b = 0) is removed when T::B doesn't exist (similar for T::A)
So when both are available, both overloads are viable, and so the call is ambiguous.
This is how the spec defines overload resolution:
Overload resolution is a mechanism for selecting the best function to
call given a list of expressions that are to be the arguments of the
call and a set of candidate functions that can be called based on the
context of the call.
the selection of the best function is the same in all cases: First, a
subset of the candidate functions (those that have the proper number
of arguments and meet certain other conditions) is selected to form a
set of viable functions. Then the best viable function is selected
based on the implicit conversion sequences needed to match each
argument to the corresponding parameter of each viable function.
For template functions, there is additional rule:
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.
These rules lead to what is called as SFINAE, in case of overload resolution for template functions .
You are right that this is not 'regular' overloading. It is called SFINAE. More information is here: https://en.wikipedia.org/wiki/Substitution_failure_is_not_an_error
If I thought I knew anything about C++ then it was that you can't overload functions by return type.
So can anyone explain what is going on here please?
class A { public: typedef int _foo; };
class B {};
template<class T>
typename T::_foo Foo(int)
{
cout << "Foo(int)\n"; return typename T::_foo();
}
template<class T>
typename T Foo(char)
{
cout << "Foo(char)\n"; return typename T();
}
int main()
{
Foo<A>(0); // Writes "Foo(int)", as expected.
Foo<B>(0); // Writes "Foo(char), expected error unable to compile template.
return 0;
}
There are two classes A and B. A defines typedef _foo, B does not. There are two overloads of function template Foo, Foo(int) and Foo(char). Foo(int) returns T::_foo, Foo(char) returns T.
Foo(0) is then called twice. This is an exact match for Foo(int) so I would expect Foo<A>(0) to compile ok, and Foo<B>(0) to fail to compile since B does not define the type _foo used in the template.
What actually happens is that Foo<B>(0) completely ignores Foo(int) and instantiates Foo(char) instead. But by the normal rules of overload resolution Foo(0) is clearly an exact match for Foo(int), and the only thing that makes Foo(char) a more viable match is the return type which should not be considered.
To verify that it is the return value that is affecting the overload resolution just add this:
template<class T>
void Bar(int) { typename T::_foo a; cout << "Bar(int)\n"; }
template<class T>
void Bar(char) { cout << "Bar(char)\n"; }
Bar<A>(0); // Writes "Bar(int), as expected.
//Bar<B>(0); // Error C2039: '_foo' : is not a member of 'B', as expected.
This makes it clear that in the absence of the return value Foo(int) is indeed the correct overload, and that if the template cannot resolve the types used from its template argument that failure to compile is the normal outcome.
You're not overloading on return type, you're specializing a function template and when the Foo<B>(int) specialization forms the invalid type B::_foo that specialization is removed from the overload set by SFINAE, leaving the Foo<B>(char) function as the only viable function.
In more detail, the call to Foo<A>(0) first performs name lookup to find all the Foo names in scope, then instantiates any function templates to find the overload candidates, then overload resolution chooses the best match.
The step of instantiating the function templates produces these two function declarations:
int Foo<A>(int);
A Foo<A>(char);
Overload resolution chooses the first one as the best match.
However when calling Foo<B>(0) the instantiations produce these declarations:
<invalid type> Foo<B>(int);
B Foo<B>(char);
The first declaration is not valid, so there is only one candidate for overload resolution, so that is the one that gets called.
In your Bar example the invalid type that gets formed during instantiation is not in "the immediate context" of the function declaration (it's in the function definition i.e. body) so SFINAE does not apply.
template<class T>
typename T::_foo Foo(int);
template<class T>
typename T Foo(char);
So your code declares this overloaded function. That's nice.
Foo<A>(0);
In this case, the compiler tries to fill out the template for the prototypes declared above, which would be:
int Foo(int);
A foo(char);
And since you're passing an integer as a parameter, the first is a better match, so the compiler uses that one.
Foo<B>(0);
Again the compiler sees this line and tries to fill out the template for the prototypes, but...
WTFDOESNTMAKESENSE?!?!? Foo(int);
A foo(char);
So clearly, the first one doesn't even make sense, so it discards that and uses the second overload. This actually has nothing to do with return types, it has to do with how template prototypes are filled out before it decides which function you mean. Here's your example rearranged to clarify:
template<class T>
int foo(T::_foo) {}
template<class T>
int foo(char) {}
int main() {
foo<A>(0); //uses the first, `int foo(int)` better than `int foo(char)`
foo<B>(0); //uses the second, because the first doesn't work with B.
This is called SFINAE, and note that it only works in very particular circumstances in template parameters, return types, and function parameters, but not the function body itself. This is why your "verification" caused an error, because it can't tell that one of the functions is invalid from the prototype, and the prototype is the only thing considered when it's deciding between overloads.
Why does compiler allow this?
#include <iostream>
using namespace std;
template<typename T>
void func(T t)
{
cout<<"The value is :"<<t<<"\n";
}
template<>
void func<int>(int d) //Template Specialization
{
cout<<"Template function\n";
}
void func(int d) //Non-template function with same name & signature
{
cout<<"Non-template function\n";
}
int main()
{
func(4);
func(4.67);
func("TENE");
}
The answer to the question lies in section 13.3.3
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,
— 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.5.2, or, if not that, ...
So amongst the three choices (non-templated func, specialization of func<int>, and the generic template func<typename T>, the non-template version of func is the best. Since there is a perfect match here, there is no reason for the compiler to even look to the templated versions of the function.
Because this code is perfectly legal. See this article for resolution rules.
I'm on a roll today. Here goes n00b question number 7:
What's the difference between explicit specialization and just regular functions when you try to overload a template function?
What's the appropriate situation to use the explicit specialization? I don't quite understand it:
#include <iostream>
template <typename s> void test(s var1);
template <> void test<int>(int var1);
int main(){
test(1);
test(1.1);
test("hello!!");
return 0;
}
template <typename s> void test(s var1){
std::cout << var1 << std::endl;
}
template <> void test<int>(int var1){
std::cout << "int " << var1 << std::endl;
}
As oppose to:
#include <iostream>
template <typename s> void test(s var1);
void test(int var1);
int main(){
test(1);
test(1.1);
test("hello!!");
return 0;
}
template <typename s> void test(s var1){
std::cout << var1 << std::endl;
}
void test(int var1){
std::cout << "int " << var1 << std::endl;
}
There really isn't a difference between an explicitly specialized template function and a non-template regular function other than the fact that when the compiler looks for a matching signature type for the function call, it will first pick a non-template function that matches the required signature before trying to instantiating any available template functions that may fulfill the required signature match.
If you are going to declare and define a function inside a header file that is not a template-function though, you will have to declare the function as inline. That is because a template function is not an actual function that is linked with a code module until it is actually instantiated. The linker then throws away that instantiation after compiling the code module. If the linker did not do this, then every time a .cpp file included the header file, the linker would complain about duplicate definitions for a function. Using the inline keyword on a non-template function has a similar effect at the compiler level, in that any time the function is used in a .cpp file, the compiler replaces that function call with the body of the function code from the inline function in the header file, and avoids the overhead of a function call with an associated stack active record setup and clean-up. Therefore the linker won't complain about duplicate definitions for a function.
I'm not an expert, but my experience is to use templates (and specialization) when I want to define different return types. You can't overload the return type of a function.
A major difference is: Explicit specializations don't participate in overloading at all.
template<typename T> void f(T const&);
template<> void f<char const*>(char const * const&);
Calling with f("hello") will not consider any explicit specializations. It will only take all templates, and deduce their template arguments. The above T will be deduced to char[6], and so the specialization won't be selected.
If you overload the function template instead, you have completely different characteristics.
template<typename T> void f(T const&);
void f(char const * const&);
Calling this, it will select the second function, because both the (char const(&)[6]) parameter of the generated specialization and the (char const * const&) parameter match the argument equally well, but the second function is a non-template function, hence it is preferred eventually.
When the compiler comes across a function call, it first looks for a non-template function definiton, then an explicitly specialized template and finally, a template definition whose signature matches with the function call.
So, for example, if you have an explicitly defined template and a template, then the complier goes for the explicitly defined template. Therefore, you should use an explicity specialzed template when you want to handle a particular datatype in a different manner from the way the template would have handled it.
Another use for explicit specialization is when you want to "overload" a function that does not take any arguments. You can use explicit specialization to give different definitions to the function to handle different datatypes.
IMHO, explicit specialization for function template should be used when, you are going to call that function using explicit template argument. e.g.
test<int>(myClass); // no argument for 'int' -> declare test() as template specialization
In other cases, you should always use normal specialization. e.g.
test(10, myClass); // argument 10 is 'int' -> test() should be normal specialized
Technically there is no difference between normal and explicit template specialization of a function. The normal specialized versions are completely independent of template functions.