Discussion:
Templates. Explicit instantiation. Part 2
(too old to reply)
Andriy R
2008-05-07 11:15:07 UTC
Permalink
Hello

Could someone explain the reason of the next compile error?
CodeGear™ C++Builder® 2007 R2 Version 11.0.2987.10779

//header-file
template <typename T>
class TestC
{
public:
void f();
};

// in cpp file
// explicit instantiation
template class TestC<double>;

// generic impl
template <typename T>
void TestC<T>::f()
{
}


// complete specialization
template <>
void TestC<double>::f()
{}

[BCC32 Error] : E2392 Template instance 'TestC<double>::f()' is already instantiated

Is this a standard rule of templates compiling?
Workaround:
1. move "template class TestC<double>;" clause in the end of cpp-file
2. change order of member function f() impl >> generic after concrete
But all cases leads to another linking error (see Part 1)
Leo Siefert
2008-05-08 11:56:22 UTC
Permalink
Post by Andriy R
template class TestC<double>;
I'm not an expert on templates, but I don't understand what you want
that line to do, but AFAICT it is at best superfluous and is the
source of your difficulties. The code will compile if the line is
places after the instantiation of TestC<double>::f(), but it appears
to have no practical effect in that case. I tested with this code and
got the expected results:

#include <iostream>
template <typename T>
class TestC {
public:
void f();
};

template <>
void TestC<double>::f() { std::cout << "double" << std::endl; }

//template class TestC<double>;

template <typename T>
void TestC<T>::f() { std::cout << "generic" << std::endl; }

int main() {
TestC<int> a;
TestC<double> b;
TestC<float> c;
a.f();
b.f();
c.f();
}

Output is:
generic
double
generic

Same results with or without the commented line included. Also tested
with the initial template declaration in a header file. Doesn't matter
which order the implementations are in.

Comeau compiler results in the same error with your original code.

- Leo
Chris Uzdavinis (TeamB)
2008-05-08 13:21:31 UTC
Permalink
Post by Leo Siefert
Post by Andriy R
template class TestC<double>;
I'm not an expert on templates, but I don't understand what you want
that line to do, but AFAICT it is at best superfluous and is the
source of your difficulties.
That line is called explicit instantiation. It forces the compiler to
instantiate the template on type <double>. One benefit to doing this
is that if you know ahead of time all the types that will be used with
your template, you *can* put the template code in a .cpp file, and
explicitly instantiate it in that .cpp file for every type with which
it will be used. Then the header does NOT need to include the source
of the template, and compile times are faster and the coupling between
implementation of the template and the code using the template is
reduced.

It is a hassle to hand-instantiate templates, but sometimes is very
beneficial. (Without this, the compiler will attempt to instantiate
the template when it is used, and at that point it must see the
definition of the template. If it doesn't see the definition, it
assumes the instantiate occurs elsewhere, and simply makes a call to
it. Eventually, the linker must find an instantiation for each call,
or the link will fail.

The problem with the original code is that the explicit instantiation
is being done before the full definition of the class is presented.
Thus, the specialization for the function f is done after the template
is instantiated... should it change the instantiation or be ignored?
This problem is detected by the compiler, which mainly is:

"Don't instantiate a template until the template's complete definition
is known."
--
Chris (TeamB);
Andriy R
2008-05-08 14:27:39 UTC
Permalink
Post by Chris Uzdavinis (TeamB)
The problem with the original code is that the explicit instantiation
is being done before the full definition of the class is presented.
Thus, the specialization for the function f is done after the template
is instantiated... should it change the instantiation or be ignored?
"Don't instantiate a template until the template's complete definition
is known."
--
Chris (TeamB);
Thank you for the good explanation.
Changing the order of specialized member function f() after it generic implementation prevents thiscompiler error even when explicit instantiation is stated at the begining of cpp file.
It's strange, because regarding the rule compiler should find best suited complete or partial spec...

But when I put explicit instantiation clause in the end of cpp-file it leads to linker error that is more surprising for me (see post "Templates. Explicit instantiation")!
[ILINK32 Error] Error: Unresolved external 'TestC<double>::f()'

Could you explain this linker-error?
Alan Bellingham
2008-05-08 15:08:52 UTC
Permalink
Post by Chris Uzdavinis (TeamB)
Post by Andriy R
template class TestC<double>;
That line is called explicit instantiation. It forces the compiler to
instantiate the template on type <double>.
Does that force instantiation of anything except the default c'tor, the
d'tor and any static data members?

Alan Bellingham
--
Team Browns
ACCU Conference 2009: to be announced
Chris Uzdavinis (TeamB)
2008-05-08 17:02:43 UTC
Permalink
Post by Alan Bellingham
Post by Chris Uzdavinis (TeamB)
Post by Andriy R
template class TestC<double>;
That line is called explicit instantiation. It forces the compiler to
instantiate the template on type <double>.
Does that force instantiation of anything except the default c'tor, the
d'tor and any static data members?
I think it instantiates everything. According to 14.7.2 p7, "The
explicit instantiation of a class template specialization implies the
instantiation of all its members not previously explicitly specialized
in the translation unit containing the explicit instantiation."

But there are enough big words in there to cause some doubt. :)
--
Chris (TeamB);
Andriy R
2008-05-08 15:02:58 UTC
Permalink
Explicit instantiation is very useful if you exactly knows all possible template class instantiation and hide implementation issues in cpp file
Post by Leo Siefert
Post by Andriy R
template class TestC<double>;
I'm not an expert on templates, but I don't understand what you want
that line to do, but AFAICT it is at best superfluous and is the
source of your difficulties. The code will compile if the line is
places after the instantiation of TestC<double>::f(), but it appears
to have no practical effect in that case. I tested with this code and
#include <iostream>
template <typename T>
class TestC {
void f();
};
template <>
void TestC<double>::f() { std::cout << "double" << std::endl; }
//template class TestC<double>;
template <typename T>
void TestC<T>::f() { std::cout << "generic" << std::endl; }
int main() {
TestC<int> a;
TestC<double> b;
TestC<float> c;
a.f();
b.f();
c.f();
}
generic
double
generic
Same results with or without the commented line included. Also tested
with the initial template declaration in a header file. Doesn't matter
which order the implementations are in.
Comeau compiler results in the same error with your original code.
- Leo
Loading...