Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why default argument can't be added later in template functions?

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';
} 
like image 226
Destructor Avatar asked Sep 02 '15 17:09

Destructor


People also ask

CAN default arguments be used with the template?

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 { };

Can template parameters have default values?

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.

Which case default argument passing in function is not allowed?

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.


1 Answers

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.

like image 100
Daveed V. Avatar answered Oct 12 '22 23:10

Daveed V.