8

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?

Danra
  • 9,546
  • 5
  • 59
  • 117
  • 1
    `C c1{};` compiles on latest clang. – Vittorio Romeo Mar 08 '17 at 11:35
  • 1
    [This answer](http://stackoverflow.com/a/16015037/598696) explains why you need `<>` - in short, it's to avoid ambiguity between templates and types. – Vittorio Romeo Mar 08 '17 at 11:37
  • 3
    *"Or perhaps C++17's standard now accepts the syntax without <>"*, in C++17 there's class template deduction that takes place here – Piotr Skotnicki Mar 08 '17 at 11:51
  • @PiotrSkotnicki welcome to post as an answer. – Danra Mar 08 '17 at 12:29
  • 2
    @Danra but I don't know the *exact* reason for not allowing a template-name as a type-specifier before (other than *because reasons*) – Piotr Skotnicki Mar 08 '17 at 12:30
  • @PiotrSkotnicki I guess the answer @Vittorio mentioned above is the *reason* - the `<>` is required to differentiate the class template from the template class. I guess this reason *is* valid in some contexts, but looks like in simple scenarios like the one in my example (more are detailed here http://en.cppreference.com/w/cpp/language/class_template_deduction), the standard just assumes you mean the template class and not the class template, so the <> aren't needed anymore. – Danra Mar 08 '17 at 13:16
  • @Danra *"the <> is required to differentiate the class template from the template class"*, that's what the semantic analysis phase is for – Piotr Skotnicki Mar 08 '17 at 13:31
  • What do people mean when they say template class? Is that the specialization? – ThomasMcLeod Mar 09 '17 at 03:15

1 Answers1

4

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-seqopt initializer

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.

Barry
  • 286,269
  • 29
  • 621
  • 977
  • According to http://en.cppreference.com/w/cpp/language/class_template_deduction deduction for variable declarations should only take place when "using a direct parenthesized or braced initializer", so perhaps latest Clang is right not to accept `C c1;` but only `C c1{};`, and latest GCC is wrong to also accept the former. – Danra Mar 08 '17 at 14:04
  • So given that `C c{};` is valid, which function call does it match: `foo()` or `foo({})`? – Piotr Skotnicki Mar 08 '17 at 14:12
  • @PiotrSkotnicki: It causes value initialization. Just like for *any use* of `Typename variablename{}`. – Nicol Bolas Mar 08 '17 at 14:14
  • @NicolBolas what you said doesn't answer my question – Piotr Skotnicki Mar 08 '17 at 14:14
  • @PiotrSkotnicki `foo()`. – Barry Mar 08 '17 at 14:14
  • 3
    @Danra Apparently the initializer restriction was lifted in Kona last week, so `C c;` will indeed be valid. – Barry Mar 09 '17 at 03:08
  • 1
    Where are you the information that the initializer requirement was removed? Just curious. – ThomasMcLeod Mar 09 '17 at 03:23
  • 1
    @ThomasMcLeod look for paper P0620R0 when the post-Kona mailing comes out – Cubbi Mar 10 '17 at 00:17
  • 1
    @ThomasMcLeod Here's the link http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0620r0.html – Danra Apr 08 '17 at 17:54