Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is <> required when specifying a template class which has defaults for all its template parameters?

Is there a good reason why <> is required when specifying a template class which has defaults for all its template parameters?

e.g.

#include <iostream>

template<typename T = int>
class C {
public:
    T obj = 0;
};

int main()
{
    C c1; // Error on almost all compilers (see note below)
    C<> c2;
    std::cout << c1.obj << " " << c2.obj << std::endl;
    return 0;
}

An example disadvantage of this is that if you have a class which is already used in various places, and you later refactor it to be a class template with default parameters for its template arguments, then you have to add <> in all the places which use the class.

Note: it looks like GCC latest HEAD (7.0.1) accepts the syntax without <>. Earlier versions do not and neither does any version of Clang. Is this a bug in the latest GCC HEAD? Or perhaps C++17's standard now accepts the syntax without <> and GCC is just ahead here?

like image 493
Danra Avatar asked Mar 08 '17 11:03

Danra


People also ask

Can template parameters have default arguments?

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 default arguments be used with the template class?

Can default arguments be used with the template class? Explanation: The template class can use default arguments.

What is the purpose of template parameter?

A template parameter is a special kind of parameter that can be used to pass a type as argument: just like regular function parameters can be used to pass values to a function, template parameters allow to pass also types to a function.

What is template What is the need of template declare a template class?

A template is a simple yet very powerful tool in C++. The simple idea is to pass data type as a parameter so that we don't need to write the same code for different data types. For example, a software company may need to sort() for different data types.


1 Answers

In C++17, this is well formed:

C c1{};

due to deduction for class templates. We'd synthesize a function for each constructor (and deduction guide) and perform overload resolution:

template <class T=int> C<T> foo();
template <class T=int> C<T> foo(C<T> const&);
template <class T=int> C<T> foo(C<T>&&);

The first one is a viable overload, and the other two are not, so deduction succeeds and the placeholder C is replaced by the deduced type C<int>.

However, grammatically, an initializer is required in [dcl.type.class.deduct]:

If a placeholder for a deduced class type appears as a decl-specifier in the decl-specifier-seq of a simple-declaration, the init-declarator of that declaration shall be of the form:

declarator-id attribute-specifier-seqoptinitializer

The placeholder is replaced by the return type of the function selected by overload resolution for class template deduction (13.3.1.8).

But C c; contains no initializer, so it doesn't fit grammatically. This is a gcc bug for allowing this. Although it seems odd to disallow this specifically. Apparently, this restriction has been lifted in Kona, so C c; will indeed be well-formed in C++17. I will update the answer once new wording comes out.


Before C++17, the statement was ill-formed simply because C is not a type. C and C<> are not the same thing. There was, and still is no, special consideration for having all defaulted template parameters. Types and class templates are different, and continue to be treated differently.

like image 59
Barry Avatar answered Sep 28 '22 15:09

Barry