Monday, February 05, 2007

Constructor templates and explicit instantiation

Well, this is going to be a lighter one. I came across this recently. Classes can have templates and constructors can be templates too. Something like this:

[CODE]

class SomeClass
{
             public:
                           template<typename T>
                           SomeClass(T t) { /*some code*/ }
};

Now, we all know that we can explicitly ask the compiler to generate the code for a specific template type parameter T of any class or any function template. But is the same possible for constructors? Let's try:

[CODE]

int main()
{
             SomeClass object<int>(10);
             SomeClass object.template SomeClass<int>(10);
}


Try compiling the code. It doesn't. Isn't it? You may try different ways, different syntaxes but the thing is you cannot ask a explicit instantiation of templatized constructors. The reason being that constructors are typical member functions. They are called without a function name. They don't have a name. I mean, they are declared by the same name as that of the class but in user code sense, they don't have a name using which they are invoked. In fact, they are not even invoked by us. That happens automatically or by the placement new syntax but you don't specify the name and hence the arguments (template arguments or function arguments).

Similar are conversion functions. Here is a note from the C++ standards 2005 draft that is quite self-explantory: (section 14.8.1 paragraph 7)

[NOTE]

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

Have fun! More, later...

3 comments:

André said...

You can do this by passing a specified type of argument (not by specifying the template parameter explicitly):

[CODE]

class SomeClass
{
protected:
void* m_pValue;
public:
template < typename T > SomeClass(T t):m_pValue((void*)t) {};
template < typename T > operator T(void) { return (T)m_pValue; }
};

int main(()
{
SomeClass scInt(10);
std::cout << (int)scInt << std::endl;
SomeClass scChar('a');
std::cout << (char)scChar << std::endl;
}

[/CODE]

Is compile- and linkable, on execution produces the following output:

[CODE]
10
a
[/CODE]

Anonymous said...

Wrong, Andre. One can perform argument type deduction (as you've shown), but it is not possible to specify a static VALUE for a template parameter.

Anonymous said...

And more importantly, it is also not possible if a template type is not one of the constructor arguments.

Like this:

struct SomeClass {
size_t a;
template < class T > SomeClass() : a(sizeof(T)) {}
}

This compiles under gcc 4.2, but it's not possible to call this constructor :(