Can the Template Parameters of a Constructor Be Explicitly Specified

Can the template parameters of a constructor be explicitly specified?

No. The C++03 standard says:

[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.] (§14.5.2/5)

Template constructor in a class template - how to explicitly specify template argument for the 2nd parameter?

Fixing your code, the following would work:

template<class T> class TestTemplate {
public:
//constructor 1
template<class Y> TestTemplate(Y * p) {
cout << "c1" << endl;
}

//constructor 2
template<class Y, class D> TestTemplate(Y * p, D d) {
cout << "c2" << endl;
}

template<class A, class B>
void foo(A a, B b) {
cout << "foo" << endl;
}
};

int main() {
TestTemplate<int> tp(new int());

tp.foo<int*, string>(new int(), "hello");

TestTemplate<int> tp2(new int(),2);
}

You cannot use T for the class template parameter and the constructor template parameter. But, to answer your question, from [14.5.2p5]:

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.

Therefore, you cannot explicitly specify template arguments for constructor.

How can I specify non-deducible template parameters on a constructor?

No, you can't specify constructor template arguments. There are a few alternatives.

  1. As indicated in the comments by @KerrekSB, you can give the constructor template a std::integral_constant parameter, which when passed as an argument, will deduce N:

Code:

#include <cassert>
#include <type_traits>

struct X
{
int i;

template<int N>
X(std::integral_constant<int, N>) : i(N)
{
}
};

int main()
{
std::integral_constant<int, 6> six;
X x(six);
assert(x.i == 6);
}

Live Example


  1. You can write a dedicated make_X<N> template wrapper that hides the integral_constant boiler-plate:

Code:

template<int N>
X make_X()
{
return X(std::integral_constant<int, N>{});
}

int main()
{
auto y = make_X<42>();
assert(y.i == 42);
}

Live Example

Explicitly-specified template parameter packs

This follows from the rules for template argument deduction.

When you explicitly specify the template parameters for func, the compiler will match it to the first parameter pack greedily. The compiler does not figure out that once you start putting ints in the parameters, it should start substituting for Is....

Instead, it will continue substituting for Ts..., and you'll get an error message along the lines of:

expected a type, but got 1

for the 3rd explicitly specified parameter.

You can see this if you specify only the Ts..., like this:

func<int, char>(E<1,2,3>{}, 1, 'a');

which compiles just fine.

Constructor with extra template argument

The correct syntax for the out-of-class definition of a template method in a template class is as follows:

template <typename A> // Class template parameters
template <typename B> // Method template parameters
Class<A>::Class() {
// ^^^
// Class template parameters

// ...
}

live example on wandbox

Template instantiation of templated class constructor

Constructors don't have names. As much is said in [class.ctor]/1. They are special members that get defined by using the name of the class. But they themselves are nameless. While C++ allows us to reference c'tors in certain contexts by using the class name, those are limited. In general, we cannot name a c'tor.

And that is where the issue lies. To explicitly specify template arguments we must use the name of the templated entity. Constructors don't have names, and so we cannot specify their arguments explicitly.

This is the subject of a note in [temp.arg.explicit] that summarizes the intent of the normative text.

7 [ 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 ]

We can still instantiate or specialize constructors, but only if the template arguments don't have to be explicitly specified (if they are deducible, or come from a default template argument). E.g

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

template X::X(int); // This will work

So Clang is not wrong to reject your code. And it's possible GCC is offering an extension. But ultimately, the standard doesn't offer a way to provide template arguments explicitly to constructor templates.


And upon further digging, there's CWG581, further confirming Clang's behavior is the intended one. It also seems to have made its way into the latest standard revision with some changes to the normative text.

Is it possible to have a templated constructor like 'template class T X(){}'?

Yes, it is possible to have such a constructor, but it's impossible to call it. All the template parameters of a templated constructor must be deduced from the parameter list or have a default value. In Your example you can't instantiate the class.

[temp.mem]

[ 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 ]



Related Topics



Leave a reply



Submit