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.
- 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 deduceN
:
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
- You can write a dedicated
make_X<N>
template wrapper that hides theintegral_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 int
s 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
Smart Pointers: Who Owns the Object
Std::Thread Pass by Reference Calls Copy Constructor
Winmain and Main() in C++ (Extended)
Determine If a Type Is an Stl Container At Compile Time
Boost_1_60_0 .Zip Installation in Windows
Why Is the Size of an Empty Class in C++ Not Zero
Why Is Template Argument Deduction Disabled With Std::Forward
C++0X Lambda Capture by Value Always Const
Is Calling Destructor Manually Always a Sign of Bad Design
View Array in Visual Studio Debugger
How to Get the Ip Address of a Local Computer
Strict Aliasing Rule and 'Char *' Pointers
Why Do Std::Shared_Ptr≪Void≫ Work
How to Print the Wchar_T Values to Console
Why Is Out-Of-Bounds Pointer Arithmetic Undefined Behaviour
Is This Key-Oriented Access-Protection Pattern a Known Idiom