tags:

views:

117

answers:

3

The below code couldn't pass the compilation, what's the consideration for this compiler error?

template<class T> void f(T t) {};

template<> void f<char>(char c = 'a') {}

Error message: Default arguments are not allowed on an explicit specialization of a function template

+6  A: 

I think that the rationale behind this error is due to the fact that the default arguments in the function template apply to its specialization as well and you are not allowed to define the default argument more than once in C++.

Consider the following:

#include <iostream>

template<class T> void f(T t = 'a') {}

template<> void f<char>(char c)
{
    std::cout << c << std::endl;
}

int main(int argc, char **argv)
{
    f<char>();
}

This will print a meaning that specialization is called with the default argument defined in the main template.

If you need a different default argument for each specialization you can use the approach illustrated below:

#include <iostream>

template<class T>
struct default_arg
{
    static T get() { return T(); }
};

template<class T> void f(T t = default_arg<T>::get()) {}

template<>
struct default_arg<char>
{
    static char get() { return 'a'; }
};

template<> void f<char>(char c)
{
    std::cout << c << std::endl;
}

int main(int argc, char **argv)
{
    f<char>();
}
vitaut
This is not very nice.. This says, that all types `T` must be able to be initialized with char.. Or to have an appropriate cast operator to char.
Kiril Kirov
@Kiril Kirov: This is just an example to illustrate the point (why the compiler gives this error).
vitaut
Yep, but still.. Anyway: +1 - for the idea, added after the edit (:
Kiril Kirov
+4  A: 

C++98 §12.7/21 "Default function arguments shall not be specified in ... the explicit specialization of a function template".

Regarding rationale I think it has to do with a call always being resolved against the primary template. A call that leaves out an argument required by the primary template, couldn't be resolved wihtout changing the lookup rules.

Alf P. Steinbach
+1 for citing the relevant part of the standard. Never was good at it =)
vitaut
Indeed, explicit specializations aren't found by name-lookup. Template argument deduction is done on the function template, and if it's only called by `f()`, it can't deduce `T`. How would it be supposed to choose `char`. One could argue one could do `f<char>()` and if an explicit specialization for `f<char>` exist that provides a default argument, it would be used. But I see little use for that and it would only further complicate template argument deduction.
Johannes Schaub - litb
+2  A: 

The selection of which particular template instance to use is based on the type of the parameter provided. Thus the selection of the explicit specialisation is made by the provisioning of a char argument - it is only at that point that the default argument (as you've codified) would come into play (where it is redundant).

It only makes sense to provide default arguments on the template declaration itself. The disadvantage is that you have to specific the appropriate specialisation yourself (which removes some of the advantages in using a default argument in the first place).

To achieve the behaviour that (I believe) you want, use the following.

template<class T> void f(T t) {}

template<> void f<char>(char c) {}

void f() { f('a'); }
CodeButcher