Template specialization of one method from a template class

Always considering that the following header containing my template class is included in at least two .CPP , this code compiles correctly:

 template <class T> class TClass { public: void doSomething(std::vector<T> * v); }; template <class T> void TClass<T>::doSomething(std::vector<T> * v) { // Do somtehing with a vector of a generic T } template <> inline void TClass<int>::doSomething(std::vector<int> * v) { // Do somtehing with a vector of int's } 

But pay attention to inline in the specialization method. It is required that the code does not have a linker error (in VS2008 there is LNK2005) due to the fact that the method is defined more than once. I understand this because AFAIK's full template specification is the same as a simple method definition.

So how do I remove this inline ? The code should not be duplicated every time it is used. I searched Google, read some questions here in SO, and tried many of the proposed solutions, but none of them were successfully built (at least not in VS 2008).

Thank!

+73
c ++ visual-studio-2008 templates specialization
Nov 12 '09 at 16:31
source share
5 answers

As with simple functions, you can use declaration and implementation. Put a header declaration:

 template <> void TClass<int>::doSomething(std::vector<int> * v); 

and put the implementation in one of your cpp files:

 template <> void TClass<int>::doSomething(std::vector<int> * v) { // Do somtehing with a vector of int's } 

Do not forget to remove the built-in (I forgot and thought that this solution would not work :)). Tested on VC ++ 2005

+60
Nov 12 '09 at 16:49
source share

You need to transfer the specialization definition to a CPP file. Specialization of a member function of a template class is allowed, even if the function is not declared as a template.

+4
Nov 12 '09 at 16:50
source share

There is no reason to remove the inline keyword.
In any case, this does not change the code value.

+1
Nov 12 '09 at 16:55
source share

If you want to delete the embedded line for any reason, then the maxim1000 solution will be absolutely correct.

In your comment, however, it seems you think that the inline keyword means that the function with all its contents is always embedded, but AFAIK, which in fact is very much dependent on your compiler optimization.

Quote from C ++ Frequently Asked Questions

There are several ways to indicate that a function is built-in, some of which include the inline keyword, others not. Regardless of how you designate a function as inline, this is a request that the compiler is allowed to ignore: the compiler can inline-expand some, all or nothing places where you call a function designated as inline. (Don’t be disappointed if this seems hopelessly uncertain. The flexibility above is actually a huge advantage: it allows the compiler to handle large functions different from small ones, plus it allows the compiler to generate code that is easy to debug if you choose the right compiler options.)

So, if you do not know that this function will really inflate your executable file or if you do not want to remove it from the template definition header for other reasons, you can actually leave it where it is without damage.

+1
Jul 06 '15 at 10:11
source share

This is a little OT, but I decided to leave it here in case this helps someone else. I googled about the template specialization that brought me here, and although @ maxim1000's answer was correct and ultimately helped me sort out my problems, I did not think it was completely clear.

My situation is slightly different (but similar enough to leave this answer, I think) than the OP. In fact, I use a third-party library with all kinds of classes that define "status types". The heart of these types is simply enum , but all classes inherit from a common (abstract) parent and provide various helper functions, such as operator overloading and the static toString(enum type) function static toString(enum type) . Each enum status is different and unrelated. For example, one enum has fields NORMAL, DEGRADED, INOPERABLE other - AVAILBLE, PENDING, MISSING , etc. My software is responsible for managing different types of statuses for different components. This happened because I wanted to use the toString functions for these enum classes, but since they are abstract, I could not instantiate them directly. I could expand every class I wanted to use, but in the end I decided to create a template class where typename would be what specific enum status I took care of. There may probably be some debate about this solution, but I felt that it was a lot less work than expanding each abstract enum class with its own and implementing abstract functions. And of course, in my code, I just wanted to be able to call .toString(enum type) and make it print a string representation of this enum . Since all enum were completely unrelated, each of them had their own toString functions which (after some research that I studied) should have been called using template specialization. It brought me here. Below is the MCVE of what I had to do to make this work correctly. And actually my solution was slightly different from @ maxim1000.

This is a (very simplified) header file for enum . In fact, each enum class was defined in its own file. This file represents the header files that are provided to me as part of the library that I use:

 // file enums.h #include <string> class Enum1 { public: enum EnumerationItem { BEARS1, BEARS2, BEARS3 }; static std::string toString(EnumerationItem e) { // code for converting e to its string representation, // omitted for brevity } }; class Enum2 { public: enum EnumerationItem { TIGERS1, TIGERS2, TIGERS3 }; static std::string toString(EnumerationItem e) { // code for converting e to its string representation, // omitted for brevity } }; 

adding this line is just to split the following file into another block of code:

 // file TemplateExample.h #include <string> template <typename T> class TemplateExample { public: TemplateExample(T t); virtual ~TemplateExample(); // this is the function I was most concerned about. Unlike @maxim1000's // answer where (s)he declared it outside the class with full template // parameters, I was able to keep mine declared in the class just like // this std::string toString(); private: T type_; }; template <typename T> TemplateExample<T>::TemplateExample(T t) : type_(t) { } template <typename T> TemplateExample<T>::~TemplateExample() { } 

next file

 // file TemplateExample.cpp #include <string> #include "enums.h" #include "TemplateExample.h" // for each enum type, I specify a different toString method, and the // correct one gets called when I call it on that type. template <> std::string TemplateExample<Enum1::EnumerationItem>::toString() { return Enum1::toString(type_); } template <> std::string TemplateExample<Enum2::EnumerationItem>::toString() { return Enum2::toString(type_); } 

next file

 // and finally, main.cpp #include <iostream> #include "TemplateExample.h" #include "enums.h" int main() { TemplateExample<Enum1::EnumerationItem> t1(Enum1::EnumerationItem::BEARS1); TemplateExample<Enum2::EnumerationItem> t2(Enum2::EnumerationItem::TIGERS3); std::cout << t1.toString() << std::endl; std::cout << t2.toString() << std::endl; return 0; } 

and this outputs:

 BEARS1 TIGERS3 

I have no idea if this is the perfect solution to solve my problem, but it worked for me. Now, no matter how many enumeration types I end up using, all I have to do is add a few lines for the toString method in the .cpp file, and I can use the already defined toString method libraries without implementing it myself and without an extension of every enum class that I want to use.

0
Jan 12 '19 at 2:50
source share



All Articles