static member function inside class template specialization - c++

I am struggling to access static member function defined inside class template.
In the header file TemplateTest.h I defined the primary class Template as:
#include<iostream>
template<class T, class U>
struct TemplateTest
{
public:
void static invoke();
/*{
std::cout << "Should not be called" << std::endl;
}*/
};
Then Source File TemplateTester.cpp I put a specialization:
#include "TemplateTest.h"
template<>
struct TemplateTest<int, bool>
{
static void invoke()
{
std::cout << "invoke<int, bool>" << std::endl;
}
};
template struct TemplateTest<int, bool>; //instantiate to resolve linker issue
I explicitly instantiated the class with so linker resolves correctly.
In the driver driver.cpp :
include "TemplateTest.h"
int main()
{
TemplateTest<int, bool>::invoke();
return 0;
}
When I compile the TemplateTest.cpp with g++ it generates the object file correctly but when I try to link it to the driver class it gives my linker error "undefined reference to `TemplateTest::invoke()"
I went through other related postings like this one but I am not trying access a function template.
Any clue is much appreciated.

You are right that the object file you create from TemplateTester.cpp will contain a symbol for the specialization you provided. This is the case because any explicit specialization causes the template to be instantiated, and it is doubly the case because you even added an explicit instantiation (which is actually unnecessary).
However, at the time when driver.cpp is compiled, the compiler does not know about the specialization, because you only include TemplateTester.h, and the specialization isn't mentioned there. So the compiler instantiates the template, of course not using the specialized definition, so you get your problem.
The Standard says (Italics by me):
(ยง14.7.3/6) If a template, a member template or a member of a class template is explicitly specialized then that specialization shall be declared before the first use of that specialization that would cause an implicit instantiation to take place, in every translation unit in which such a use occurs; no diagnostic is required. If the program does not provide a definition for an explicit specialization and either the specialization is used in a way that would cause an implicit instantiation to take place or the member is a virtual member function, the program is ill-formed, no diagnostic required. An implicit instantiation is never generated for an explicit specialization that is declared but not defined. [...]
So you need to make both, the declaration and the definition of the specialization known to the compiler when it works on driver.cpp. The best way of doing this is by adding the entire specialization to TemplateTester.h.
Note, again, that an explicit instantiation is not actually required.

There are several problems :
you do not need to explicitly instantiate fully specialized template
if you want to put your static method in the header, then use inline. Otherwise you will get multiple instances and linker problems
template specializations you put in the header, and define methods in the source files
if you do not want something to be called in a template, you don't need to define it. You'll get compiler errors, and that means catching errors earlier.
// TemplateTest.h
#include<iostream>
template<class T, class U>
struct TemplateTest;
template<>
struct TemplateTest<int, bool>
{
inline static void invoke()
{
std::cout << "invoke<int, bool>" << std::endl;
}
};
// main.cpp
include "TemplateTest.h"
int main()
{
TemplateTest<int, bool>::invoke();
}
Another way is to change the header, and add the source file.
// TemplateTest.h
#include<iostream>
template<class T, class U>
struct TemplateTest;
template<>
struct TemplateTest<int, bool>
{
static void invoke();
};
// TemplateTest.cpp
#include "TemplateTest.h"
void TemplateTest<int, bool>::invoke()
{
std::cout << "invoke<int, bool>" << std::endl;
}

Related

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.

Partial Template specialization definition outside of class definition

I am having a little trouble with a template specialization. I have looked for other answers, and thought I found the solution in this thread - Partial template specialization outside class definition - however it turns out that does not solve my problem.
I am trying to do some template specialization based on enum values to remove the need for unnecessary run-time polymorphism. When I define the template functions within the class body, it works OK, but when I move the definitions outside of the class template the compiler cannot match the signature.
My actual scenario is interfacing with an API that uses named objects for which each class of objects I am representing with an enum value. The objects are not directly related to each other, but they have very similar resource management / manipulation mechanisms. I initially tried using traits, but because I sometimes need to use completely different function signatures, traits didn't work out as I hoped.
Anyway, here is a cut down example of the problem I am facing.
Dog bark works, because it is defined in the class definition, but Cat meow does not, because it cannot find a declaration of meow. If I merge the definition and declaration cat meow will work.
Is there any way to partially specify templates in this manner? The reason being is that I'd like the dependency on external API's kept to a source file rather than in the header file.
enum class AnimalType { Dog, Cat, };
template<AnimalType Type> struct A;
template<>
struct A<AnimalType::Dog>
{
// OK
void bark() { std::cout << "woof"; }
};
template<>
struct A<AnimalType::Cat>
{
void meow();
};
// Cannot match
template <>
void A<AnimalType::Cat>::meow()
{
}
GCC 4.9 complains
scratchpad/animal.h:105: error: template-id 'meow<>' for 'void <(AnimalType)1>::meow()' does not match any template declaration
void A<AnimalType::Cat>::meow()
Thanks
This:
template<>
struct A<AnimalType::Cat> {
void meow();
};
declares a template specialization with a non-template method. But this:
template <> void A<AnimalType::Cat>::meow()
implies specialization of a template method. Since A<AnimalType::Cat> is already fully-specialized, it doesn't need the template <> here.
Use this instead:
void A<AnimalType::Cat>::meow() {
std::cout << "meow\n";
}
and consider for comparison this template method:
template<>
struct A<AnimalType::Cat> {
template <AnimalType> void greet();
};
template <>
void A<AnimalType::Cat>::greet<AnimalType::Cat>() {
std::cout << "purr\n";
}
template <>
void A<AnimalType::Cat>::greet<AnimalType::Dog>() {
std::cout << "flee\n";
}
Like this works:
// template <>
void A<AnimalType::Cat>::meow()
{
}
As you are defining a member function of the concrete class A<AnimalType::Cat>.

Redeclaration error for a templated function

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() { ... }

Specializing a template member function?

I would like to have several different function definitions for a member function in a templated class. Something like this:
template <typename T>
class MyClass
{
void Foo();
T val;
//other functionality and data
};
//handles all types
template <typename T>
void MyClass<T>::Foo()
{
return val;
}
//handles a special type in a different way
template <>
void MyClass<float>::Foo()
{
return val + 5.0f;
}
I've tried implementing this as above and get a linker error for every special type I try to explicitly instantiate. The linker error mentions that the function has already been previously defined. Maybe I'm looking in the wrong places but I couldn't find any resources to help me figure out this problem :(
Q. Is this possible? If so, how do you do this and why does it work?
Thanks!
Here is a workaround that I frequently use. As it as been said before, you have to specialize the complete template. The idea is to make the method you want to specialize a static member of some struct (that should be nested and private for encapsulation reasons). Like this:
template< typename T >
class MyClass {
struct PerformFoo {
static void doFoo () {
std::cout << "Foo for general type" << std::endl;;
}
};
public:
void Foo () {
PerformFoo::doFoo();
}
};
template<>
struct MyClass< float >::PerformFoo {
static void doFoo () {
std::cout << "Foo for float" << std::endl;;
}
};
Now in your main, the code
MyClass< int > myInt;
myInt.Foo();
MyClass< float > myFloat;
myFloat.Foo();
prints
Foo for general type
Foo for float
on your terminal. By the way: this does not involve any performance penalty with modern compilers. Hope this helps you.
By defining the specialized member function as inline function you will get rid of the link error complaining the specialized member function having been defined elsewhere.
//handles a special type in a different way
template <>
inline void
MyClass<float>::Foo()
{
return val + 5.0f;
}
The reason being that a specialized function is no longer a function template, but a concrete function. Therefor it will be compiled several times when compiling source files that includes this header file which is why you get the "already defined" error.
Another solution is to move the implementation of the specialized function out of the header file and put it into the source file, meanwhile, declare the specialized function in the header file. Note that the declaration of the specialized member function must stay outside of the class definition:
/// Declare the specialized function in the header file but outside the
/// class definition.
template <> void MyClass<float>::Foo()
/// Define the specialized function in .cpp file:
template <>
void
MyClass<float>::Foo()
{
return val + 5.0f;
}
I've tried implementing this as above and get a linker error for every special type I try to explicitly instantiate.
What does that mean? If you explicitly specialize the template you cannot explicitly instantiate it anymore for the same template arguments. The whole purpose of an explicit specialization is to prevent the instantiation of it (which is a generated specialization) in favor of your explicit specialization.
So your description does not make sense to me. Just remember that you need to put definitions of templates and member functions of class templates in the header instead of in the .cpp file if you want to instantiate them implicitly. And that explicit specializations need to be declared to everyone who uses their template with their arguments.
// put this specialization into the header, for everyone to see
template <> void MyClass<float>::Foo();
It is not possible. When you specialize a template, you must specialize the entire template, which in this case means the entire class.
You can make foo a template function inside the template class. It is not exactly the same as what you are asking for, but it might meet your needs.
Update:
template<typename T> class Foo {
public:
template<typename R> void foo() {printf("This is foo\n");}
template<> void foo<float>() {printf("This is foo<float>\n");}
};
Or:
template<typename T> class Foo {
public:
template<typename R> void foo() {printf("This is foo\n");}
//template<> void foo<float>() {printf("This is foo<float>\n");}
};
template<> template<> void Foo<float>::foo<float>() {
printf("This is foo<float>\n");
}
along with:
int main(int argc,char * argv[])
{
Foo<int> iFoo;
iFoo.foo<int>();
Foo<float> fFoo;
fFoo.foo<float>();
return 0;
}
generates:
This is foo
This is foo<float>
The syntax for calling foo is a bit awkward.

Composition of template class

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()
{
}