Zeroshade
Zeroshade

Reputation: 573

out-of-line constructor template works in GCC fails in Clang

The following code works fine in GCC, but fails to compile in clang:

#include <iostream>
#include <string>

template <typename T>
struct A {
template <typename C>
  A(const C& c) { std::cout << "base" << std::endl; }
};

template <>
template <>
A<std::string>::A<std::string>(const std::string& s) { 
  std::cout << s << std::endl; 
}

int main()
{
  std::string f("foo");
  A<std::string> a(f);
  A<std::string> b(1.2);
}

GCC outputs:

foo
base

But Clang gives the following error:

source_file.cpp:14:17: error: out-of-line constructor for 'A' cannot have 
template arguments
A<std::string>::A<std::string>(const std::string& s) {              
                ^~~~~~~~~~~~~~
1 error generated.

I just wanted to confirm if anyone knew if clang was correct in disallowing this or if it's a bug in clang. If I remove the explicit template argument, then clang works just fine with deducing the template argument, compiles and produces the correct output. It's only with the explicit template argument that it fails to compile, and I can't think of anything in the standard that would disallow that.

Thanks

Upvotes: 2

Views: 1010

Answers (2)

Mihayl
Mihayl

Reputation: 3911

As you have already noticed, you don't need to repeat the template argument in the constructor template specialization because it's deduced. A<std::string>::A should be enough.

template <>
template <>
A<std::string>::A(const std::string& s) { 
  std::cout << s << std::endl; 
}

The main problem is that the constructors actually have no names. There is still an open C++ standard issue 581. Can a templated constructor be explicitly instantiated or specialized? with the following note from 2006:

It was observed that explicitly specifying the template arguments in a constructor declaration is never actually necessary because the arguments are, by definition, all deducible and can thus be omitted.

Clang comments mention [class.qual]p2[8][9] and issue 1435[4] as argument to complain and reject template arguments.

6.4.3.1 Class members [class.qual]

[...]

2 In a lookup in which function names are not ignored and the nested-name-specifier nominates a class C:

— (2.1) if the name specified after the nested-name-specfier, when looked up in C, is the injected-class-name of C (Clause 12), or

[...]

the name is instead considered to name the constructor of class C.

The only place that mentions that conversion member function templates and constructor member function templates cannot be used with explicit template arguments is a no-normative note.

17.6.2 Member templates [temp.mem]

[...]

5 A specialization of a conversion function template is referenced in the same way as a non-template conversion function that converts to the same type. [...]

[Note: Because the explicit template argument list follows the function template name, and because conversion member function templates and constructor member function templates are called without using a function name, there is no way to provide an explicit template argument list for these function templates. —end note]

Upvotes: 3

xskxzr
xskxzr

Reputation: 13040

Clang is correct.

Quoted from [temp.mem]/5:

[ Note: Because the explicit template argument list follows the function template name, and because conversion member function templates and constructor member function templates are called without using a function name, there is no way to provide an explicit template argument list for these function templates. — end note ]

Upvotes: 3

Related Questions