Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Default template parameters in using-declaration and instantiation

Edit:
Apparently, GCC allows instantiating a class template without a parameter list (when the parameters are defaulted), which is non-compliant (Clang is compliant).
I'm guessing the reason for requiring the brackets (even when the parameter list is empty) is to make it explicit that it is a template instantiation, as opposed to an actual type.
So I am steering my original question toward the differences between the class template and function template cases: why, in the second snippet, is it allowed to call a without brackets, in contrast to the instantiation of A in the first snippet? And why is it not allowed for b?


Original:
A class template with only default parameters can be instantiated without any parameter list (see A below).
However, if an alias to that class template is defined via a using-declaration as a template with the same default parameters (see B below), then its instantiation requires a parameter list (possibly empty).
Similarly, defining an alias to the class template as an actual type (see C below) requires a parameter list (again, possibly empty).
Is there a reason behind this?
template<int i = 1>
struct A {
    operator int() { return i; }
};

template<int i = 2>
using B = A<i>;

// using C = A;    <-- error: missing template arguments after 'A'
using C = A<>;

int main() {
    A a; // Edit: Actually should require brackets: A<> a;
    // B b;    <-- error: missing template arguments before 'b'
    B<> b;
    C c;
}

Live on Coliru

I have tried building a similar scenario with a function template instead of a class template, and there is a slight difference in the last case (C): no parameter list is required if the return type is specified in the definition of a. I think I understand why, but I would welcome some insights. Otherwise, both cases are similar to the class template ones.

template<int i = 1>
auto a() { return i; }
// auto a() -> int { return i; }
// if the return type is specified, c can be defined as commented below

template<int i = 2>
auto b = a<i>;

// auto c = a;    <-- error: unable to deduce 'auto' from 'a'
auto c = a<>;

int main() {
    a();
    // b();    <-- error: missing template arguments before '(' token
    b<>();
    c();
}

Live on Coliru

Also, are there significant differences between modern C++ standards (C++11 to C++20)? I am mostly interested in the C++17 case, but I would love to know if these things have changed, or are going to.
From what I've seen, in C++14, a class template instantiation requires a parameter list anyway, whereas a function template call does not. And I haven't found differences between C++17 and C++2a with GCC.

like image 403
Nelfeal Avatar asked Oct 12 '18 09:10

Nelfeal


1 Answers

Template arguments [temp.arg]/4 (§12.3/4)

When template argument packs or default template-arguments are used, a template-argument list can be empty. In that case the empty <> brackets shall still be used as the template-argument-list.

Same wording for C++17 in §17.3/4, for C++14 & C++11 in §14.3/4.

Explicit template argument specification [temp.arg.explicit] (§12.9.1/3):

If all of the template arguments can be deduced, they may all be omitted; in this case, the empty template argument list <> itself may also be omitted.

Same wording for C++17 in §17.8.1/3, for C++14 & C++11 in §14.8.1/3.


Your

template<int i = 2>
auto b = a<i>;

is a variable template for which no argument deduction will occur.

like image 182
Swordfish Avatar answered Nov 15 '22 13:11

Swordfish