Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Explicit Instantiation of Templated Constructors

Consider the code below:

#include <iostream>

class Test {
   public:
    Test() {std::cout << "I am called\n";};

    template <typename T>
    Test(T t);
};

template <typename T> Test::Test(T t){ std::cout << t << "\n";};

// Explicit template instantiation
template Test::Test<int>(int);
template Test::Test<double>(double);

int main() {
    Test test;
    Test test2(12342);
    Test test3(3.1415);
    return 0;
}

This code compiles and works fine with GCC (my version is 13.2). Output is as I expect:

I am called
12342
3.1415

Clang (my version is 16.0.0) throws an error and the code does not compile:

<source>:14:16: error: qualified reference to 'Test' is a constructor name rather than a type in this context
template Test::Test<int>(int);
               ^
<source>:14:20: error: expected unqualified-id
template Test::Test<int>(int);
                   ^
<source>:15:16: error: qualified reference to 'Test' is a constructor name rather than a type in this context
template Test::Test<double>(double);
               ^
<source>:15:20: error: expected unqualified-id
template Test::Test<double>(double);
                   ^
4 errors generated.

Can anyone help me understand the problem or direct me to a source?

like image 639
Abdullah Ali Sivas Avatar asked Feb 02 '26 19:02

Abdullah Ali Sivas


1 Answers

A template argument list can't be given to a constructor per [temp.arg.explicit]/1 requiring the template argument list for a function specialization to follow the "function template name", which constructors do not have. Constructors are named via the injected-class-name of their containing class instead of having a name like other function templates. (Constructors can be referred to in declarative forms only. When writing e.g. Test(1, 2) as an expression, then Test refers to the class Test, not its constructor, which can't be named or called explicitly.)

Resolution of CWG 581 also reaffirms that in 2019 for C++20 and as a defect report against previous standard editions with wording that explicitly excludes template argument lists on constructors in [temp.arg.explicit]/2.

So the explicit instantiation can't have a template argument list, but it also doesn't need one. Instead

template Test::Test(int);
template Test::Test(double);

is sufficient. Template argument deduction is done on explicit instantiation declarations for function templates, so this will choose the expected specializations.

This is not an actual restriction in the language, because a constructor template specialization that can't have its template arguments deduced this way would be useless as it also could never be chosen by overload resolution to be called. Constructors are never called with explicitly specified template arguments either.

GCC shouldn't accept the code without diagnostic to be conforming. Before CWG 581 the intent might not have been completely clear, but the resolution seems very clear in its wording to me. GCC lists the defect report's implementation as unknown status. Clang's behavior is conforming.

like image 173
user17732522 Avatar answered Feb 04 '26 09:02

user17732522



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!