C++ standard section 8.3.6.4 says that
For non-template functions, default arguments can be added in later declarations of a function in the same scope. [...]
But my question is that why it isn't allowed for template functions? What is the rationale for not allowing addition of default arguments in later declarations in same scope for template functions?
Consider this program which compiles fine. (non template function) (see live demo here.)
#include <iostream>
int f(int a,int b,int c=3);
int f(int a,int b=9,int c); // default argument in middle, ok allowed
int main()
{
f(3);
f(3,6);
f(3,6,9);
return 0;
}
int f(int a,int b,int c)
{
std::cout<<a<<' '<<b<<' '<<c<<'\n';
return 0;
}
But following fails in compilation. (template function) (see live demo here.)
#include <iostream>
template <typename T>
void f(T a,int b,int c=3);
template <typename T>
void f(T a,int b=9,int c); // compiler error why???
int main()
{
f(3);
f(3,6);
f(3,6,9);
return 0;
}
template <typename T>
void f(T a,int b,int c)
{
std::cout<<a<<' '<<b<<' '<<c<<'\n';
}
You cannot give default arguments to the same template parameters in different declarations in the same scope. The compiler will not allow the following example: template<class T = char> class X; template<class T = char> class X { };
Just like in case of the function arguments, template parameters can have their default values. All template parameters with a default value have to be declared at the end of the template parameter list.
Default arguments are only allowed in the parameter lists of function declarations and lambda-expressions, (since C++11) and are not allowed in the declarations of pointers to functions, references to functions, or in typedef declarations.
This is a historical limitation that was added fairly early in the standardization process (it was there in C++98, but not in the ARM).
I don't recall the exact reason (and neither does my colleague, who was almost certainly there when the decision was made). However, I have a guess...
Back then, all-but-one compilers instantiated templates by replaying tokens through the parse. Some barely parsed templates at all. Consider:
template<class T> struct S {
T f(T); // (1)
};
template<class T> T S<T>::f(T p = 42) { return p; } // (2)
S<int> s; // Causes the "real" parsing of (1), but not (2).
int r = s.f(); // (3)
When resolving call (3), older compilers therefore often only had access to the instantiated declaration (1), while (2) was still not really parsed (just token-buffered). As a result, such compilers were unaware of the added default argument in (3).
Is suspect caution made the committee therefore decide to more generally disallow added default arguments in templates.
That limitation is probably less (technically) justified today, since other standard requirements have since resulted in the need to parse templates in their generic form (though, e.g., MSVC still doesn't do so AFAICT). That said, it might still be a bit of a pain to implement, because default arguments would now potentially have to be instantiated in various different contexts.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With