#include <iostream>
using namespace std;
template <typename A, typename B> void test(A a, B b) { cout << "first" << endl;}
template <typename A> void test(A a, int b) { cout << "second" << endl;}
template <> void test(int a, int b) { cout << "special" << endl;} //this is a specific instantiation, of which template?
int main(){
test(2,3); //got: "special"
test<int>(2,3); //got: "special"
test<int, int>(2,3); //got: "first". So specialisation is linked to second template, why?
}
What is the rule for selecting which template the explicit specialization is an instantiation of? It seems like it could be ambiguous. From the output of the last function call it is indicated to me that the specialisation is for the second function template definition (the explicit template arguments select the first template, but the specialisation is not used - so it must be a specialisation of the second template), why exactly? It seems like any relevant info should be in [14.7.3] of N3337 but to the best of my ability I could not find what I was looking for. Might the program even be in error by doing this?
Granted it might be rare that someone would have to worry about this but I'm still curious as to why it happens.
Related
I was trying to understand Template Partial and Full Specialization and have this below code:
#include <iostream>
using namespace std;
//Template in C++is a feature. We write code once and use it for any data type including user defined data types.
//What if we want a different code for a particular data type - Template Specialization
template <class T, class Y>
void fun(T a, Y b)
{
cout << "The main template fun(): " << a << " " << b << endl;
}
//If a specialized version is present, compiler first checks with the specialized version and then the main template.
//Compiler first checks with the most specialized version by matching the passed parameter with the data type(s) specified in a specialized version.
template<>
void fun(const char* a, const char* b)
{
cout << "Specialized Template for int type: " << a << " " << b << endl;
}
//Partial specialization allows to specialize only some arguments of a class template, as opposed to explicit full
template<class T>
void fun(T a, int b)
{
cout << "Partial Template specialization for int type: " << a << " " << b << endl;
}
int main()
{
fun<int, int>('a', 10);
fun< const char*, const char*>("Hello", "Morning");
fun<float, float>(10.14, 19.89);
}
Note that in main I am specifying the data types and below is the output:
The main template fun(): 97 10
Specialized Template for int type: Hello Morning
The main template fun(): 10.14 19.89
But when I execute the main code below way:
int main()
{
fun('a', 10);
fun("Hello", "Morning");
fun(10.14, 19.89);
}
This is the output I get:
Partial Template specialization for int type: a 10
Specialized Template for int type: Hello Morning
The main template fun(): 10.14 19.89
So what does the actual C++ Template Partial / Full specialization states - do we need to specify the data types in template argument to invoke - also in many websites I have seen following signature for Partial specialization:
template<class Y, const char*>
void fun(Y a, const char* b)
Rather than
template<class Y>
void fun(Y a, const char* b)
Similarly for full specialization - what is the exact way to write and call Partial / Full template specialized function / class?
The comments cover the general principles, but there are specific questions here worth answering. First, a lemma: the template parameters of a function template need not be related to its parameter types:
template<class T>
T make_1() {return T(1);}
auto v=make_1<std::vector<std::string>>(); // {""}
template<class T,class U>
void f(std::conditional_t<sizeof(T)<sizeof(U),int,long> i);
This is why your “partial specialization” is not a candidate for fun<int, int>(…). The template arguments aren’t just instructions for how to build the parameter list one by one, but rather must match the actual template parameters for the function template in question. There’s only one of those, so they don’t match. True partial specializations still use the primary template’s template parameter list; they just match against certain patterns in the list of arguments for it.
Meanwhile,
template<class Y, const char*>
void fun(Y a, const char* b)
is valid but doesn’t mean what you think for the same reason: const char* in the template parameter list introduces an unnamed (non-type) template parameter of type const char*, so that you’d have to use it like
char global;
void g() {fun<char,&global>('a',"foo");}
(with no deduction for Y!), only to have that &global ignored entirely,
Please help to understand below 3 different syntax's
#include <iostream>
using namespace std;
template <typename T>
class Demo {
public:
void print_type(){
if(is_same<int,T>())
cout << "Int type" << endl;
if(is_same<float,T>())
cout << "float type" << endl;
}
};
//1. fun
template<typename T>
void fun(Demo<T> a){
cout << "In <T>fun(Demo<T>)" <<endl;
a.print_type();
}
//2. fun
template<typename T=int,class D=Demo<T> >
void fun(D a){
cout << "In <T,class>fun(Demo)" <<endl;
a.print_type();
}
// 3. fun
template<typename T=int,template <typename T> class D=Demo >
void fun(D<T> a){
cout << "In <T,template>fun(Demo<T>)" <<endl;
}
int main()
{
fun(Demo<int>());
fun(Demo<float>());
return 0;
}
the function calls in main are calling the first version of fun
if I comment out any two definitions of fun, the third one is called
What is the difference between the three fun definitions? How can I call all 3 without commenting out any of them?
Let's take a look at our three functions:
template <typename T> void fun(Demo<T> ); // (1)
template <typename T, typename D> void fun(D ); // (2)
template <typename T, template <typename> class D> void fun(D<T> ); // (3)
Let's consider the second. D will be deduced from the first argument, but T does not appear in any of the function parameters - it is a non-deduced context. As such, it must be specified explicitly by the caller in order to be considered. You do not specify it, so it's a deduction failure and is thrown out of the overload set.
Now (1) and (3) are both viable candidates for arguments of type Demo<int> and Demo<float>. In both cases, the two functions take identical arguments that are exact matches for the caller and are both function templates - so the last tiebreaker is to consider which function template is more specialized (this is also called function template partial ordering). (1) can only accept types that look like Demo<T>. (3) can accept Demo<T> but also OtherTemplate<T> or YetAnotherClass<T>. It's more generic - so we prefer to call (1). The rules for this are pretty complicated, but you can do more searching if you're interested. A simpler example might be:
template <typename T> void foo(T ); // (4)
template <typename T> void foo(T* ); // (5)
foo(new int(42));
Both candidates are viable, (4) matches with T = int* and (5) matches with T = int. But (4) matches anything whereas (5) only matches pointers, which makes it more specialized and thus the best viable candidate.
If you comment out (2), nothing changes - it wasn't a viable candidate anyway. But if you comment out (1), then we call (3) because (3) becomes the only viable candidate (and thus, trivially, the best viable candidate).
I have the following code:
#include <iostream>
#include <vector>
using namespace std;
struct A{};
struct B: public A {};
template <typename T>
void foo(const T& obj) { cerr << "Generic case"<< endl;}
void foo(const A& a) {
cerr << "Specific case" << endl;
}
int main() {
vector<int> v;
foo(v);
B b;
foo(b);
A a;
foo(a);
}
Output is
Generic case
Generic case
Specific case
Why is it that foo(const A& a) is not being chosen for the B object ?
Curiously enough, if I removed the templated method and just have the following:
#include <iostream>
#include <vector>
struct A{};
struct B: public A {};
//template <typename T>
//void foo(const T& obj) { cerr << "Generic case"<< endl;}
void foo(const A& a) {
cerr << "Specific case" << endl;
}
int main() {
B b;
foo(b);
A a;
foo(a);
}
The code compiles and the output is:
Specific case
Specific case
Why is the presence of the templated method making such a difference?
Edit: How can I force the compiler to choose the free method for classes derived from A in the presence
of the templated method?
No conversion is necessary for the call to foo(const B&) which the template instantiation yields thus it is the better match.
When a function call is seen by the compiler, every base function template has to be instantiated and is included in the overload set along with every normal function. After that overload resolution is performed. There is also SFINAE, which allows an instantiation of a function template to lead to an error (such a function would not be added to the overload set). Of course, things aren't really that simple, but it should give the general picture.
Regarding your edit: There is only one method to call. What else could there be as output?
Yes, it is a bit surprising but inheritance and template don't mix so well when it come to overload resolution.
The thing is, when evaluating which overload should be selected, the compiler chooses the one that necessitates the least conversions (built-in to built-in, derived-to-base, calls to non-explicit constructors or conversion operators, etc...). The ranking algorithm is actually pretty complex (not all conversions are treated the same...).
Once the overloads are ranked, if the two top-most are ranked the same and one is a template, then the template is discarded. However, if the template ranks higher than the non-template (less conversions, usually), then the template is selected.
In your case:
for std::vector<int> only one overload matches, so it is selected.
for A two overloads match, they rank equally, the template one is discarded.
for B two overloads match, the template rank higher (no derived-to-base conversion required), it is selected.
There are two work-arounds, the simplest is to "fix" the call site:
A const& ba = b;
foo(ba);
The other is to fix the template itself, however this is trickier...
You can hardcode that for classes derived from A this is not the overload you wish for:
template <typename T>
typename std::enable_if<not std::is_base_of<A, T>::value>::type
foo(T const& t) {
std::cerr << "Generic case\n";
}
However this is not so flexible...
Another solution is to define a hook. First we need some metaprogramming utility:
// Utility
template <typename T, typename Result = void>
struct enable: std::enable_if< std::is_same<T, std::true_type>::value > {};
template <typename T, typename Result = void>
struct disable: std::enable_if< not std::is_same<T, std::true_type>::value > {};
And then we define our hook and function:
std::false_type has_specific_foo(...);
template <typename T>
auto foo(T const& t) -> typename disable<decltype(has_specific_foo(t))>::type {
std::cerr << "Generic case\n";
}
And then for each base class we want a specific foo:
std::true_type has_specific_foo(A const&);
In action at ideone.
It is possible in C++03 too, but slightly more cumbersome. The idea is the same though, an ellipsis argument ... has the worst rank, so we can use overload selection on another function to drive the choice of the primary one.
#pmr's answer explains why the templated function is preferred in your example. To force the compiler to pick your overload instead, you can make use of SFINAE to drop the templated function from the overload set. Change the templated foo to
template <typename T>
typename std::enable_if<!std::is_base_of<A, T>::value>::type
foo(const T& obj) { cerr << "Generic case"<< endl;}
Now, if T is A or a class derived from A the templated function's return type is invalid and it will be excluded from overload resolution. enable_if is present in the type_traits header.
I am learning function templates just now and I wanted to research a bit rules of function templates instantiation. So I've written the following code:
#include <iostream>
template <typename>
int check(int x) {
return x * 2;
}
int main() {
std::cout << check<double>(10) << std::endl; // #1
std::cout << check<>(10) << std::endl; // #2
std::cout << check(10) << std::endl; // #3
return 0;
}
The lines #1, #2 and #3 are not compiled all together, each try I leave only one of them and comment the rest.
So, when #1 is enabled, I have no compilation errors and the correct answer "20" is printed. As I understand, "check<"double">" invokes template instantiation mechanism so "int check(int)" function is really created (the type of template parameter doesn't have any influence).
When #3 is enabled, I have a compilation error "error: no matching function for call to 'check(int)'", which is reasonable, since I am trying to call to "check(int)" function which doesn't exist. My question is regarding #2 case: in this case I get the same "error: no matching function for call to 'check(int)'". Shouldn't call "check<>(10)" trigger template instantiation mechanism as well?
You don't put any template parameter in the <>. How can compiler know which template function to instantiate? Please notice that your template function is:
template <typename>
int check(int x)
If you change it to this:
template <typename T>
int check(T x)
then check<>(10) should be fine because the complier can know the type from the parameter.
I have to say that usually template doesn't go that way:(
Try this one:
template<typename T>
T check(T x){
return x*2;
}
The only template instantiation you'll get is with
check<double>(10)
The others don't instantiate the template. Also for the full power of function templates include the template argument as
template<typename T>
T check(T x) {
return x*2;
}
Then using the power of template argument deduction you can call
check(10.0); // instantiates check<dobule>
check(3); // instantiates check<int>
or
a = MyObject();
check(a); // instantiates check<MyObject>
#2 would be valid if the template argument could be deduced.
#include <iostream>
template <class T>
void foo(T t)
{
std::cout << "Template " << t << '\n';
}
void foo(int n)
{
std::cout << "Not template " << n << '\n';
}
int main()
{
foo(10); //calls non-template function
//because matching non-template preferred over function templates
foo<>(10); //calls the template function, empty brackets indicate you want
//the template overload, type is deduced from passed argument.
}
Another possibility, if the function template had default arguments (only legal in C++11).
template <class T = void>
int foo()
{
return 10;
}
int main()
{
return foo<>(); //same as foo<void>();
}
If you don't pass a template argument, it is equivalent to looking for the function without a template argument (i.e. it doesn't instantiate the template). The added <> means nothing in this case because there are is no overloading.
Since the function you have doesn't actually use the template for anything and the compiler thus can't infer the type T, but if you write it like this:
template <typename T>
T check(T x) {
return x * 2;
}
Then all 3 cases will work, since it infers the type T. See https://stackoverflow.com/a/797632/888641 for more explanation.
Note: You can use typename or class, they do the exact same thing here.
I have a visitor class resembling this:
struct Visitor
{
template <typename T>
void operator()(T t)
{
...
}
void operator()(bool b)
{
...
}
};
Clearly, operator()(bool b) is intended to be a specialization of the preceding template function.
However, it doesn't have the template<> syntax that I'm used to seeing before it, declaring this as a template specialization. But it does compile.
Is this safe? Is this correct?
Your code is not a template specialization, but rather a non-templated function. There are some differences there. The non-templated operator() will take precedence over a templated version (for an exact match, but type conversions will not take place there) but you can still force the templated function to be called:
class Visitor
{
public: // corrected as pointed by stefanB, thanks
template <typename T>
void operator()( T data ) {
std::cout << "generic template" << std::endl;
}
void operator()( bool data ) {
std::cout << "regular member function" << std::endl;
}
};
template <> // Corrected: specialization is a new definition, not a declaration, thanks again stefanB
void Visitor::operator()( int data ) {
std::cout << "specialization" << std::endl;
}
int main()
{
Visitor v;
v( 5 ); // specialization
v( true ); // regular member function
v.operator()<bool>( true ); // generic template even if there is a non-templated overload
// operator() must be specified there (signature of the method) for the compiler to
// detect what part is a template. You cannot use <> right after a variable name
}
In your code there is not much of a difference, but if your code needs to pass the template parameter type it will get funnier:
template <typename T>
T g() {
return T();
}
template <>
int g() {
return 0;
}
int g() {
return 1;
}
int main()
{
g<double>(); // return 0.0
g<int>(); // return 0
g(); // return 1 -- non-templated functions take precedence over templated ones
}
What you have here is function overloading; to obtain template specialization, you indeed need the template <> syntax. However, you should be aware that these two approaches, even if they may seem identical, are subtly different, and even the compiler might get lost when choosing the right function to call. Listing all the possible cases would be a little too long for this answer, but you might want to check Herb Sutter GoTW #49 on the subject.
Oh, it'll compile. It just won't be a template function. You'll have a regular non-template function instead of a template specialization.
It's safe, and actually likely what you want as well. The Visitor pattern is normally implemented by overloading. Specializing function templates isn't really a good idea anyway.
What you did is not template serialization, but function overloading. It is safe.
P.S. It's difficult to say whether it's correct or not, without knowing what you're trying to achieve. Keep in mind that no matter is it template or overloaded function, your operator will be chosen in compile time. If you need to run-time dispatch, you need polymorphism, not overloading. Well, you probably know it anyway; just in case.
You have
void operator()(bool b) that is non
templated function
template< typename T > void
operator()(T t) which is a separate
base template that overloads the
above
You could have a full specialization of the second one as in template<> void operator(int i) which would only be considered when void operator()(bool b) did not match.
The specialization of base template is used to select which of the base template methods to call. However in your case you have a non-templated method that will get considered first.
The article Why Not Specialize Function Templates? gives quite good explanation of how the method is selected.
In sumary:
Non template functions are
considered first (this is your plain
operator()(bool) above)
Function base templates get checked
second (this is your templated
function), the most specialized base-template is selected and then if it has specialization for the exact types that specialization is used otherwise the base template is used with 'the correct' types (see explanation in the article)
Example:
#include <iostream>
using namespace std;
struct doh
{
void operator()(bool b)
{
cout << "operator()(bool b)" << endl;
}
template< typename T > void operator()(T t)
{
cout << "template <typename T> void operator()(T t)" << endl;
}
};
// note can't specialize inline, have to declare outside of the class body
template<> void doh::operator()<>(int i)
{
cout << "template <> void operator()<>(int i)" << endl;
}
template<> void doh::operator()<>(bool b)
{
cout << "template <> void operator()<>(bool b)" << endl;
}
int main()
{
doh d;
int i;
bool b;
d(b);
d(i);
}
You get calls to:
operator()(bool b) <-- first non template method that matches
template <> void operator()(int i) <-- the most specialized specialization of templated function is called