Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it valid to write the template type's parameter list in a constructor declaration?

Tags:

c++

templates

Old GCC 4.1.2 accepts, and new GCC 4.5.1 accepts, the following program.

But is it actually correct? What does the standard say about declaring a constructor with the type's template parameter like this?

(I find it interesting that I'm not allowed to do the same in the out-of-line definition.)

#include <iostream>
template <typename T>
struct Foo {
   Foo<T>(); // <---
};

template <typename T>
Foo<T>::Foo() {
  std::cout << ":)";
}

int main() {
   Foo<int> f;
}

The reason I ask is that it was proposed in comments on this answer that GCC may be in error here.

like image 534
Lightness Races in Orbit Avatar asked Dec 26 '11 13:12

Lightness Races in Orbit


1 Answers

I will put a mail copy of a possible DR I recently sent out on Christmas here

Is the following code well formed?

template<typename T>
struct A {
  A<T>();
};

The several compilers that I tested (clang, g++ and comeau conline) accept this. Indeed 12.1 does not forbid this (A<T> is a name of that class and is not a typedef-name), but 8.3p1 says

An unqualified-id occurring in a declarator-id shall be a simple identifier except for the declaration of some special functions (12.3, 12.4, 13.5) ...

A constructor is a special member function, but the list of cross references does not include 12.1. Does that mean that the above code is ill-formed? Or is this an accidental omission?

If you do the same in an out-of-line definition, you will try to pass template arguments to a constructor. This is valid code

struct A {
  template<typename T> A();
};

template<> A::A<int>() { }

The spec says that when the injected class name is used in a qualified name when looking into the scope of the class (just as in A::A), then when name lookup accepts function/constructor names, the injected class name reference will be translated to be resolved to the constructor(s) of that class (if the name lookup context only accepts types, then the name will remain the injected class name, and will denote the class type). After A::A, name lookup is complete and yields the constructor. The <int> can then only be parsed as a template argument list. If there is no template among your constructors, your code will be invalid.

like image 68
Johannes Schaub - litb Avatar answered Oct 28 '22 13:10

Johannes Schaub - litb