I used to do what suggested here https://isocpp.org/wiki/faq/templates#separate-template-fn-defn-from-decl to separate template header and implementations. We basically explicitly instantiate the desired template at the end of .cc file so that the compilation unit contains enough information for the linker to work with.
I recently learnt that we only need to explicitly instantiate a class constructor to be able to create an instance. For example,
// .h file
template<typename T>
class A {
public:
A(T& t) : t_(t) {};
void PublicMethod();
private:
void PrivateMethod();
T& t_;
};
// .cc file
template<typename T>
void A<T>::PublicMethod() { PrivateMethod; return;}
template<typename T>
void A<T>::PrivateMethod() {
// Do some work.
return;
}
// Here I only instantiate the constructor and public interface.
template A::A(int);
template void A<int>::PublicMethod();
// In main, I can do following.
int main() {
A<int> a(2);
a.PublicMethod();
}
The part I am not clear is:
if I instantiate the public method, does it automatically instantiate all relevant private methods as well automatically?
No, if you explicitly instantiate a member (including a constructor), then only the definition for that member will be explicitly instantiated.
The explicit instantiation may cause implicit instantiation of other members of the class, but that isn't enough to use these members in a different translation unit. If you do not intent to use the private members in a different translation unit though, then it would be sufficient to explicitly instantiate the public/protected member functions.
If you want to explicitly instantiate all class members, you should explicitly instantiate the class template specialization itself:
template class A<int>;
template A::A(int);
This is not correct. Your constructor expects a reference, so it should be int& instead of int. Furthermore A is the template, not a specialization of it. You must specify a specialization:
template A<int>::A(int);
Related
I have a template class defined :
template <class T>
class TempClass
{
...
};
If I want to make an object of this class in let's say some MyClass.h to access functions of template class, how shall I pass the argument of the template?
I tried to do the following:
class MyClass{
public:
TempClass<T> temp;
}
Sure, as supposed it does not work, as T is not defined in MyClass, so I am a bit lost how do it correctly.
Thanks.
If you want MyClass to be a template as well, you would do it like this:
template<typename T>
struct MyClass {
TempClass<T> temp;
};
(You could also use class instead of struct, but since all members are public, you don't really need default private.)
If you don't want MyClass to be a template, you will need some concrete type to substitute in for T. For example:
struct MyClass {
TempClass<string> temp;
};
Pedantic: Technically TempClass isn't a template class, it's a class template. A class template isn't actually a class, it's a template that can be used to create individual classes that are themselves template classes. Thus, TempClass is a class template, while TempClass<string> is a template class --- a class that is created by instantiating a template.
Templates are not classes. Are. as it name means, templates wich helps the compiler to create classes. That is, if you have a template class template<typename T> class Foo{};:
template<typename T>
struct Foo
{
T attribute;
};
Its only a template which the compiler uses to generate different versions of Foo, each for a specified type. When you instantiate a template, that is, tells the compiler you need that class generated with a specified type, the compiler generates a version of Foo code replacing the template argument with the specified type:
int main()
{
Foo<int> foo_int_variable;
Foo<bool> foo_bool_variable;
}
The compiler after seeing that two instances, generates code like this:
struct __Foo_int
{
int attribute;
};
struct __Foo_bool
{
bool attribute;
};
So the code of main is translated to this:
int main()
{
__Foo_int foo_int_variable;
__Foo_bool foo_bool_variable;
}
So the answer is: You need to specify what type you need, to let the compiler to generate the correct template instantiation.
If the class that uses Foo, like in your example, don't need a specific instantiation of Foo, needs a generic version of Foo, you could make that class a template too.
You can instantiate your template like this, for example, to instantiate for int:
class MyClass
{
public:
TempClass<int> temp;
};
But if you still want you MYClass to be generic, you can make it template too and define it like this:
template<typename T>
class MyClass
{
public:
TempClass<T> temp;
};
and let the any MyClass object instantiation to define parameter T, for example:
MyClass<int> class;
I have a setup where a templated function is inheriting another templated function.
template <typename DataType>
class ClassBase
{
virtual void InitModel(const cv::Mat& data) {};
}
template <typename DataType>
class ClassDerived : public ClassBase<DataType>
{
void InitModel(const cv::Mat& data) {};
}
Now I try to implement two specializations and one general templating for InitModel in ClassDerived in an implementation file
template<>
void ClassDerived<float>::InitModel(const cv::Mat& data)
{
// initialize some things
}
template<>
void ClassDervied<cv::Vec3b>::InitModel(const cv::Mat& data)
{
// initialize some things
}
template<typename DataType>
void ClassDerived<DataType>::InitModel(const cv::Mat& data)
{
// initialize some things
}
Before I wrote this, I did not have any specializations and it was working fine.
As soon as I added specialization, I get an error saying there was a redeclaration of the specification function. The weird part is that the redeclaration points out to the same line no. in the same file.
Since it was working fine before specialization, I expect the file isn't being read twice.
So, why would such an error start popping up as soon as the specializations are added ?
The error is :
/other/workspace/perception/perception_kit/object_detection/include/perception_kit/object_detection/grimson_GMM_templated_impl.tpp:129:
multiple definition of
`perception_kit::GrimsonGMMGen::InitModel(cv::Mat const&)'
CMakeFiles/test_obj.dir/src/object_detection_templated_test_platform.cpp.o:/other/workspace/perception/perception_kit/object_detection/include/perception_kit/object_detection/grimson_GMM_templated_impl.tpp:129:
first defined here
Is the problem because I am trying to derive a templated class or something else ?
Now I understand that for some, it might be a trivial problem but I have spent considerable time before I posted it here.
The base class is in BaseClass.h (its implemented as an abstract class)
The derived class declaration is in DerivedClass.h
The derived class declaration is in DerivedClass.tpp and is included in DerivedClass.h
You already defined the base template code inline in the header (with an empty body) so you can't redefine it again later. I suspect that's the source of your problem here, NOT the specializations.
You need to declare that you have specializations for those types. Otherwise, when the compiler in a different translation unit instantiates the template it will generate code for the member functions based on the primary template. When you try to link those generated functions with your specializations the linker will see multiple definitions of the specializations.
// Header
template <typename T>
struct test {
void f() {}
};
template <>
void test<int>::f(); // Declare the specialization
// Implementation (cpp, not included by client code)
template <>
void test<int>::f() { ... }
Note that function specializations are no longer templates, but regular functions. If different translation units include the definition of the function, then they will generate the code in multiple translation units. If you want to do that, then you can skip the declaration of the specialization and provide the definition directly, but you will need to make it inline:
// Implementation (if in header/included by user code)
template <>
inline void test<int>::f() { ... }
I've just been reading about template explicit instantiation:
template struct MyStruct<long>;
It was described as "quite rare", so under what circumstances would it be useful?
One of the use cases is to hide definitions from the end-user.
tpl.h:
template<typename T>
void func(); // Declaration
tpl.cpp:
template<typename T>
void func()
{
// Definition
}
template void func<int>(); // explicit instantiation for int
template void func<double>(); // explicit instantiation for double
main.cpp
#include "tpl.h"
int main()
{
func<double>(); // OK
func<int>(); // OK
// func<char>(); - Linking ERROR
}
Explicit instantiation is designed to optimize template libraries usage providing some of (mostly used) template instances in compiled binary form instead of source code form. This will reduce compile and link time for end-user applications. E.g. std::basic_string<char> and std::basic_string<wchar_t> can be explicitly instantiated in STL distribution avoid work on its instantiation in each translation unit.
Explicit instantiation is also useful when you want to encapsulate template implementation and you want this template to be used only with well-known set of types. In this case you can place only declarations of template functions (free or members) in header file (.h/.hpp) and define them in translation unit (.cpp).
Example:
// numeric_vector.h
//////////////////////////////////////////////////
template <typename T> class numeric_vector
{
...
void sort();
};
// numeric_vector.cpp
//////////////////////////////////////////////////
// We know that it shall be used with doubles and ints only,
// so we explicitly instantiate it for doubles and ints
template class numeric_vector<int>;
template class numeric_vector<double>;
// Note that you could instantiate only specific
// members you need (functions and static data), not entire class:
template void numeric_vector<float>::sort();
template <typename T> void numeric_vector<T>::sort()
{
// Implementation
...
}
Also explicit instantiation can be useful when you need instantiated type from template but inside some syntax construction that doesn't trigger instantiation itself, e.g. some compiler-specific meta-feature like __declspec(uuid) in Visual Studio.
Note the difference with another technique that could be used for implementation encapsulation - explicit specialization. With explicit specialization you must provide specific definition for each type to be specialized. With explicit instantiation you have single template definition.
Consider the same example with explicit specialization:
Example:
// numeric_vector.h
//////////////////////////////////////////////////
template <typename T> class numeric_vector
{
...
void sort();
};
template <> class numeric_vector<int>
{
...
void sort();
};
template <> class numeric_vector<double>
{
...
void sort();
};
// Specializing separate members is also allowed
template <> void numeric_vector<float>::sort();
// numeric_vector.cpp
//////////////////////////////////////////////////
void numeric_vector<int>::sort()
{
// Implementation for int
...
}
void numeric_vector<double>::sort()
{
// Implementation for double
...
}
void numeric_vector<float>::sort()
{
// Implementation for float
...
}
Having an explicit specialization allows you to hide the implementation, which, as you know, is usually impossible with templates.
I've seen this technique only once in a library that handled geometry, and they'd provide their own vector class.
So you could use
lib::Vector<MyShape>
with some basic functionality that lib::Vector provided, and basic implementations, and if you used it with their classes (some, not all)
lib::Vector<lib::Polygon>
you would use the explicit specialization. You wouldn't have access to the implementation, but I'm betting some hardcore optimizations were going on behind the scenes there.
If you really don't like defining template functions in header files, you can define the functions in a separate source file and use explicit template instantiation to instantiate all the versions you use. Then you only need a forward declarations in your header file instead of the complete definition.
When I want to define a method declared in a template class, but that the method doesn't depend on the template parameters, have I to define it in the include files as :
template class<typename T>
void MyClass::myMethod()
{
...
}
or may I define it in the cpp file as :
void MyClass::myMethod()
{
...
}
?
Thanks.
You'll need to define your method like this:
template class<typename T>
void MyClass<T>::myMethod()
{
// Method Body
}
The reason for this is that the method actually is dependent on the template parameter. Remember that every method has access to the special variable this; during the method call this is actually a parameter passed to the method. this changes in type depending on the template parameter specified during object instantiation and, as such, all methods must be template methods in order to accommodate all forms of this.
Well, if the method doesn't depend on template parameter, you can only do that with inheritance AFAIK.
The downside: more code + inheritance
The upside: (much) less code generated, depending on what parts of your code actually are template dependent. In the below example, method NonDependentMethod will only generate one assembly while DependentMethod will generate as many as there are different template parameters (just one in this case, but make a MyClass<float> and you have two, etc).
#include <iostream>
using namespace std;
class MyClassBase
{
public:
void NonDependentMethod();
};
template <class T> class MyClass : public MyClassBase
{
public:
void DependentMethod(T param);
};
void MyClassBase::NonDependentMethod()
{
cout << "NonDependentMethod" << endl;
}
template<class T> void MyClass<T>::DependentMethod(T param)
{
cout << "DependentMethod " << param << endl;
}
int main() {
// your code goes here
MyClass<int> cls;
cls.NonDependentMethod();
cls.DependentMethod(2);
return 0;
}
Put it in the header file.
The member function is still a member of the class template, and you'd have to write:
template <typename T> void MyClass<T>::myMethod() { /* ... */ }
As with all template member functions, this isn't actually a real function yet; it only generates a real function when the class template is instantiated. So the full template definitions have to be visible to everyone who instantiates the template, and the usual way of doing this is by putting everything in the header.
(Note that member functions of class templates are themselves considered function templates, and you can actually specialize them: template <> void MyClass<int>::myMethod() { }.)
You need to do it this way:
template class<typename T>
void MyClass<T>::myMethod()
{
...
}
It's not the method that is templated, it's the class.
You can have a templated method in a non-templated class, a non-templated method in a templated class (your case) and a templated method in a templated class, and of course a non-templated method in a non-templated class.
You have to define it in an even other way. The method itself may not (directly) depend on the template parameter, but the class to which it belongs certaily does, no? As such, the method indirectly depends on the template parameter too:
template class<typename T>
void MyClass<T>::myMethod()
{ // ^^^ -- note
...
}
I have a template class:
template<typename A, typename B>
class A {
};
In another .h file
template<typename A, typename B>
class A; //forward declaration
How could I declare m_A over here? I keep getting C++ forbids declaration of A with no type error:
class B {
A* m_A;
};
If you don't know the types that you want to instantiate A with when inside of B, then you will have to also make a template out of B
template<typename A1, typename B1>
class B
{
A<A1, B1>* m_A;
};
Either that, or you would have to instantiate A as a specific type, i.e.,
class B
{
A<Type_1, Type_2>* m_A;
};
Declare m_A with some specific types for A:
class B
{
A<int, char>* m_A;
}
If you B is such that you don't know a priori what types should be used in the m_A declaration, perhaps B needs to be template class and you'd use those type parameters in the declarion of m_A.
Templates are nice little peculiar beasts. The template definition must be available for the compiler at the place of instantiation, so the most common pattern is defining the template in the header so that each translation unit that uses the templated methods (and thus instantiates them) will have access to the definition.
Alternatively, you can provide the template definitions in a single translation unit, but you will have to ensure that you are instantiating the template for all the types for which you use it in the whole program.
// header
template <typename T> struct A
{
void foo( T );
}
// single translation unit
#include "header"
template <typename T> // template member definitino
void A<T>::foo( T x ) {
std::cout << "A(" << x << ")" << std::endl;
}
template struct A<int>; // explicit instantiation for int
template struct A<double>; // explicit instantiation for double
// main
#include "header"
int main() {
A<int> ai;
ai.foo( 5.5 ); // will print 5 (int rounded down)
A<double> ad;
ad.foo( 5.5 ); // will print 5.5
A<char> ac;
ac.foo( 'a' ); // linker error, A<char>::foo undefined
}
Because in general templates are meant to be used with any type through the program, defining the template methods in a single translation unit and using explicit instantiation is not a good idea. On the other hand, in the few cases where you need to control the set of types for which the template is instantiated, or under a few other circumstances (reducing large compile times [*]) you might want to follow this second approach. But again, in the general case, it is simpler to define the member functions in the header, and again it is simpler to defined them inside the class definition.
[*] Templates are compiled in all translation units in which they are used, which means that if you instantiate A<int>::foo in 5 different translation units, the compiler will compile it 5 times, and then the linker will discard 4 of the instantiations. In some cases where the template is complex, it might be an advantage to compile it once in one translation unit and just call it from the others. Note that with explicit instantiation, all member functions are compiled, while with implicit instantiation (at the place of use) only those members that are actually used will get compiled, so depending on the situation, explicit instantiation may be more costly than implicit instantiation (in classes with many members)
template<typename A>
void B<A>::function()
{
}
Btw, do not separate definitions and declarations while writing a template class.
EDIT:
changed < to < and > to >
Before that code looked like:
template
void B::function()
{
}