extern template does not work for gcc? - c++

C++11 introduced a feature called 'extern template' which indicates that template instance exists in other translate unit.(Am I right?)
This(http://www.youtube.com/watch?v=3annCCTx35o) lecture also tells that if you specify extern template and don't include instantiation, the linker will produce error.(around 2:25 in the video)
So, I've tried to build next code:
#include <iostream>
template<class T>
struct Foo
{
static constexpr int type_size = sizeof(T);
};
extern template struct Foo<int>;
int main()
{
std::cout<< Foo<int>::type_size << std::endl;
return 0;
}
I expected the build will fail because this file does not contain explicit instantiation nor specialization, but gcc just builds it up the result runs well.
What am I missing? Or, am I misunderstanding something? Or, does not gcc support extern template well?
Update
I've tried a class with non-inline function, and extern template works as expected!
#include <iostream>
template<class T>
struct Foo
{
static void print(T t);
};
template<class T>
void Foo<T>::print(T t) { std::cout << t << std::endl; }
extern template struct Foo<int>;
// template struct Foo<int>;
int main()
{
Foo<int>::print(1);
return 0;
}
Above source is not built without the commented line.
Thank you all guys!

if you specify extern template and don't include instantiation, the linker will produce error.
No, not necessarily. There is only a problem if you actually use the template. You're using a compile-time constant defined as a static member of that template, but that is replaced by the constant's value at compile-time. And after that replacement, there is no longer any use of the template, so there is no need for a definition of the template.

Related

Does template explicit instantiation work with forward-declared-types?

If I have a template class with some method defined in the .cpp file instead of the .h file, I can use explicit instantiation to get the compiler to avoid unresolved externals.
But would it work if the explicit instantiation is declared using a forward-declared type ?
template <typename T> struct Template
{
void someFunc(); //defined in the .cpp file
}
class A;
template Template<A>;
Would it work if A is finally not defined and Template<A> not used ?
First of all. The compiler only generates code if the template is instantiated (in your example no code is generated because there is no instantiation). Second, you pass a type template argument. Here the compiler would be allowed to safely create an instance.
In your example you do not use the type somewhere, but if you would e.g. to define a function, my first sentence would apply again, and the function is just generated upon instantiation somewhere.
Just at this moment the compiler must have all the knowledge to generate the code.
// Example program
#include <iostream>
template <typename T> struct Template
{
void someFunc(); //defined in the .cpp file
};
class A;
Template<A> foo;
However, if you create a template taking a non-type parameter. It will fail because the type definition is incomplete, as you were concerned of.
// Example program
#include <iostream>
#include <string>
class A;
template <A parm> struct Template
{
void someFunc() {
parm.foo();
}
};
A a;
using foo = Template<a>;
The same for this example. Here you would create an object a and of course the compiler needs to know more about the type. This is why it fails.
// Example program
#include <iostream>
template <typename T> struct Template
{
T a;
};
class A;
Template<A> foo;
Hope this helps.

Linking of template object files - different behavior with clang and gcc

There has been a lot questions about different behavior between gcc and clang. However i did not find the solution for my problem yet.
I use templates and i want to spread the definition and implementation of the class. I read about it (a lot) i am aware of the different possibilities. I choose the specific declaration, which templates i want to support. With:
template class Temp<char>;
template class Temp<double>;
I choose which templates i support, which actually works, if i put those lines at the end of the template.cc file. However with gcc i also can write it in the header file. Clang does not support it, i get linking errors.
But why? What is wrong with the declaration of used templates in the header file???
This is my toy example:
template.hh
#pragma once
#include <iostream>
template<typename T>
class Temp
{
public:
Temp(T data);
virtual ~Temp (){};
void print();
private:
T data_;
};
//Only gcc can support this
//template class Temp<char>;
//template class Temp<double>
template.cc
#include "template.hh"
template<typename T>
Temp<T>::Temp(T data): data_(data)
{
}
template<typename T>
void Temp<T>::print()
{
std::cout << data_ << " " << sizeof(data_) << std::endl;
}
//Delete those, if it is used in header
template class Temp<char>;
template class Temp<double>;
test.cc
#include "template.hh"
int main(int argc, char *argv[])
{
Temp<char> temp = Temp<char>('c');
temp.print();
Temp<double> temp2 = Temp<double>(1.0);
temp2.print();
return 0;
}
Desired output:
c 1
1 8
Explicit template instantiation belongs in the ".cc" implementation file, not the header. If you want to declare it in the header, you can do so using extern:
extern template class Temp<char>;
extern template class Temp<double>;
This will avoid the multiply-defined symbols that you are probably experiencing with Clang otherwise.
It may be that GCC supports explicit instantiation in the header file, but this does not mean it is correct C++, only that GCC is being liberal in this case. Don't rely on that.
An explicit instantiation of a function template is a definition. Explicit instantiation of a class template is a short-hand for instantiating all [non-template] member functions of the class template. Having multiple definitions of an entity in C++ results in a violation of the ODR-rule (One Definition Rules). Violations of the ODR-rule do not need to be diagnosed.
As a result, explicit instantiations of template belong into a ".cc" file. If you want to declare that a template will be explicitly instantiated in some translation unit, you can use extern template declarations, e.g.:
template <typename> void f();
template <typename> class F { /*...*/ };
extern template void f<int>();
extern template class F<int>();
extern template declarations allow templates to be defined in the header but inhibit implicit instantiation. Instead, the extern template declaration promises that there will be one translation unit providing an explicit instantiation.

C++ template explicit instantiation

I have working code like this.
#include <iostream>
struct A{
template<typename T>
void foo(T val);
};
template<typename T> void A::foo(T val)
{
std::cout << val << std::endl;
}
// link template "against" int
template void A::foo(int val);
// #include header here
int main(){
A a;
a.foo(12);
}
Template is in separate CPP file, but linking works, because of explicit instantiation:
template void A::foo(int val);
Then I did some re-factoring, and code looks like this:
#include <iostream>
template<typename G>
struct A{
template<typename T>
void foo(T val);
};
template<typename G>
template<typename T> void A<G>::foo(T val)
{
std::cout << val << std::endl;
}
// link template "against" int - not working
//template<typename G>
//template void A<G>::foo(int val);
int main(){
A<float> a;
a.foo(12);
}
How can I "link" T=int, but keep G "unknown"?
It is called explicit instantiation.
You can't do this, because G is unknown and it is not a single type. It is rather a set of types.
You can not do this. To actually produce a code from a template (I guess that's what you call link), the compiler need to know all the template parameters.
So you are left with the standard options for template instantiation: either explicitly tell the compiler what T and G will be used, either let the compiler see full code for the template member wherever you use it (that is, include the code in header).
TL;DR you can't.
In your case I'd just specify the type you intend to use
template void A<float>::foo(int val);
or (rather bulky) explicitly instantiate all the types G could be used for.
There is no way you can explicitly instantiate the template if G cannot be deduced.
Notice that linking works not because this syntax is a linker command but because your compiler is producing code that is later found at link-time. See more here

Can I exclude some methods from manual template instantiation?

We have complex template classes that have some methods which will not work with certain policies or types. Therefore, when we detect those types (at compile time, using type-traits) we fire a static assertion with a nice message.
Now we do a lot of manual template instantiation as well. Partly it is so that the methods are forced to compiler to syntax check the methods. It also reduces compile time for the library user. The problem is that the static assertions are always fired and consequently we cannot manually instantiate the template class in question.
Is there a workaround for this?
EDIT: To make it clearer, here is an example (the explicit instantiation in this case will fail on someFunc1():
// header
template <typename T>
class someClass
{
void someFunc() {}
void someFunc1() { static_assert(false, assertion_failed); }
};
// source
template someClass<int>; // Explicit instantiation
EDIT2: Here is another example. This time you can compile it to see what I mean. First compile right away. The code should compile. Then Uncomment [2] and the static assertion should fire. Now comment out [2] and Uncomment [1]. The static assertion will fire because you are explicitly instantiating the template. I want to avoid removing explicit instantiation because of the benefits that come with it (see above for benefits).
namespace Loki
{
template<int> struct CompileTimeError;
template<> struct CompileTimeError<true> {};
}
#define LOKI_STATIC_CHECK(expr, msg) \
{ Loki::CompileTimeError<((expr) != 0)> ERROR_##msg; (void)ERROR_##msg; }
template <typename T>
class foo
{
public:
void func() {}
void func1() { LOKI_STATIC_CHECK(sizeof(T) == 4, Assertion_error); }
};
template foo<int>;
//template foo<double>; // [1]
int main()
{
foo<int> a;
a.func1();
foo<double> b;
//b.func1(); //[2]
return 0;
}
You can't have both: you can't have a static assertion to prevent instantiation and explicitly instantiate the type! This is an obvious contradiction. What you can have, however, is conditionally included functionality even though it is somewhat a pain in the neck: If a certain member function is not supposed to be supported for certain types, you can move this function into a base class which conditionally has it. This way you wouldn't use a static assertion but just remove the member function. I realize that this introduces interesting other problems, e.g. with respect to the location of member variables, but I think in the context you are describing this is the best you can get.
Here is a quick example of how this could look like:
template <typename T, bool = std::numeric_limits<T>::is_integer> struct foo_base;
template <typename T> struct foo_base<T, false> { /* intentionally left blank */ };
template <typename T> struct foo_base<T, true> { void foo() { /*...*/ } };
template <typename T>
struct Foo: foo_base<T> { /* .... */ };
template struct Foo<int>; // will have foo()
template struct Foo<double>; // will not have foo()
Alright, so if you're forcing the instantiation of all methods using explicit instantiation, you can't get away with any compile time tricks to prevent instantiation of the offending methods, such as enable_if. It'd be easy enough to move the error to runtime, but that's undesirable.
I think the best you can do is move the error to link time, which will statically ensure that the program does not contain a code path that could potentially call the prohibited function, but the error messages won't be very helpful to anyone that doesn't know about the restriction you're imposing. Anyway, the solution is to declare a specialization of the prohibited member functions but not define them:
template<typename T>
struct Foo {
void bar() {
std::cout << "bar\n";
}
void baz() {
std:: cout << "baz\n";
}
};
template<> void Foo<int>::baz(); // use of Foo<int>::baz() will resolve to this specialization, and linking will fail
template struct Foo<int>;
template struct Foo<char>;
int main() {
Foo<int> f;
f.bar();
// f.baz(); // uncommenting this line results in an ugly link time error
Foo<char> b;
b.bar();
b.baz(); // works with Foo<char>
}
The static asserts no longer help give nice error messages when a mistake is made in client code, but you might want to leave them in because they'll fire if you forget to provide a specialization.
enable_if is a flexible mechanism for precise template methods targeting, may be what you are after. Example:
#include <string>
#include <iostream>
#include <boost/utility.hpp>
#include <boost/type_traits.hpp>
#include <boost/static_assert.hpp>
template <class T> class mywrapper
{
T _value;
template <class V>
typename boost::enable_if<boost::is_scalar<V>, void>::type printval_(V const& value)
{
BOOST_STATIC_ASSERT(boost::is_scalar<V>::value);
std::cout << "scalar: " << value << std::endl;
}
template <class V>
typename boost::enable_if<boost::is_compound<V>, void>::type printval_(V const& value)
{
BOOST_STATIC_ASSERT(boost::is_compound<V>::value);
std::cout << "compound: " << value << std::endl;
}
public:
mywrapper(T const& value):_value(value) { }
void printval() { printval_(_value); }
};
template class mywrapper<int>;
template class mywrapper<std::string>;
int main()
{
mywrapper<int> ival(333);
mywrapper<std::string> sval("test");
ival.printval();
sval.printval();
return 0;
}
I did not get an opportunity to test enable_if as suggested by bobah but I did come up with a solution that does not require boost and that satisfies my original requirement to a good extent (I say good and not full, will explain at the end)
The solution is to put a dummy template on the code that will fail if compiled under some selected types and is fine under others. So:
struct dummyStruct {};
#define DUMMY_TEMP typename dummy
#define DUMMY_PARAM dummyStruct
namespace Loki
{
template<int> struct CompileTimeError;
template<> struct CompileTimeError<true> {};
}
#define LOKI_STATIC_CHECK(expr, msg) \
{ Loki::CompileTimeError<((expr) != 0)> ERROR_##msg; (void)ERROR_##msg; }
template <typename T>
class foo
{
public:
void func() {}
template <typename T_Dummy>
void func1() { LOKI_STATIC_CHECK(sizeof(T) == 4, Assertion_error); }
};
template foo<int>;
template foo<double>; // [1]
int main()
{
foo<int> a;
a.func1<DUMMY_PARAM>();
foo<double> b;
//b.func1<DUMMY_PARAM>(); //[2] - this is a static error
return 0;
}
In all of my template code, these kind of functions (i.e. the ones that have static asserts OR work on some types and may fail on others by using type traits [in which case there is a selection of several different functions for different types]) are hidden from the client. So in my implementation, adding the extra dummy parameter is an OK compromise.
As a bonus, it lets me know that this function is designed to be used by only certain types. Furthermore, my original problem of explicit instantiation is solved by this simple technique.

Declaration of template class member specialization

When I specialize a (static) member function/constant in a template class, I'm confused as to where the declaration is meant to go.
Here's an example of what I what to do - yoinked directly from IBM's reference on template specialization:
===IBM Member Specialization Example===
template<class T> class X {
public:
static T v;
static void f(T);
};
template<class T> T X<T>::v = 0;
template<class T> void X<T>::f(T arg) { v = arg; }
template<> char* X<char*>::v = "Hello";
template<> void X<float>::f(float arg) { v = arg * 2; }
int main() {
X<char*> a, b;
X<float> c;
c.f(10); // X<float>::v now set to 20
}
The question is, how do I divide this into header/cpp files? The generic implementation is obviously in the header, but what about the specialization?
It can't go in the header file, because it's concrete, leading to multiple definition. But if it goes into the .cpp file, is code which calls X::f() aware of the specialization, or might it rely on the generic X::f()?
So far I've got the specialization in the .cpp only, with no declaration in the header. I'm not having trouble compiling or even running my code (on gcc, don't remember the version at the moment), and it behaves as expected - recognizing the specialization. But A) I'm not sure this is correct, and I'd like to know what is, and B) my Doxygen documentation comes out wonky and very misleading (more on that in a moment a later question).
What seems most natural to me would be something like this, declaring the specialization in the header and defining it in the .cpp:
===XClass.hpp===
#ifndef XCLASS_HPP
#define XCLASS_HPP
template<class T> class X {
public:
static T v;
static void f(T);
};
template<class T> T X<T>::v = 0;
template<class T> void X<T>::f(T arg) { v = arg; }
/* declaration of specialized functions */
template<> char* X<char*>::v;
template<> void X<float>::f(float arg);
#endif
===XClass.cpp===
#include <XClass.hpp>
/* concrete implementation of specialized functions */
template<> char* X<char*>::v = "Hello";
template<> void X<float>::f(float arg) { v = arg * 2; }
...but I have no idea if this is correct. Any ideas?
Usually you'd just define the specializations inline in the header as dirkgently said.
You can define specializations in seperate translation units though if you are worried about compilation times or code bloat:
// x.h:
template<class T> struct X {
void f() {}
}
// declare specialization X<int>::f() to exist somewhere:
template<> void X<int>::f();
// translation unit with definition for X<int>::f():
#include "x.h"
template<> void X<int>::f() {
// ...
}
So yes, your approach looks fine. Note that you can only do this with full specializations, thus it is often impractical to do this.
For details, see e.g. Comeaus template FAQ.
Put them all in a hpp file. Make the specializations and anything you define outside the class inline -- that'll take care of multiple definitions.
To answer one of your questions: is code which calls X::f() aware of the specialization, or might it rely on the generic X::f()?
If the compiler sees a definition which matches its requirements, then it will use it. Else it will generate normal function calls.
In your first code snippet, you supply a generic definition for X<T>::f(T arg), so the compiler will instantiate that for any T apart from float.
If you were to omit the generic definition, then the compiler would generate calls to, say, X<double>::f(double) and the linker would go searching for the definition which might end with a linker error.
To summarise: You can have everything in headers, because as templates you won't get multiple definitions. If you only have declarations, you will need definitions elsewhere for the linker to find later.
Using template void X<float>::f(float arg) { v = arg * 2; } instead.