Specializing a template member function? - c++

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.

Related

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>.

Defining member function of explicitly specialized class outside of the class definition

I'm seeing an error related to templates (compiler is Visual Studio 2012) that I don't understand. Here's the code, boiled down to the essentials:
// Templated class - generic
template <typename T>
class Test
{
public:
void WorksFine() {} // Comiples and works as expected at runtime
void Problem();
};
// Templated class - expicit specialization for T = int.
template <>
class Test<int>
{
public:
void WorksFine() {} // Comiples and works as expected at runtime
void Problem();
};
// The definition below compiles and works fine at runtime.
template<typename T> void Test<T>::Problem() {}
// The definition below gives error C2910.
template<> void Test<int>::Problem() {printf("In Test::Problem(int instantiation)\n");}
For the WorksFine method, the function definition is inside the explicitly specialized class definition, and everything is fine. But for the Problem method, when I define the method outside the explicitly specialized class definition, I get error C2910
Why is this? Error C2910 indicates that the problem is that Test::Problem() is already defined. But it is not defined inside the class...there is no function definition only a declaration.
It seems pretty lame to be able to do something or not depending on where you choose to put the function definition, which I always though was more of a style/syntax decision, not a functionality/semantics decision. Am I missing something?
You don't need the template<>. Just write:
void Test<int>::Problem() {printf("In Test::Problem(int instantiation)\n");}
The template<> syntax on a member specialization is required where explicitly instantiating a member on its own; it is omitted when defining a member of an already existing specialization.
template<typename T> struct X { static int i; };
template<> int X<int>::i = 0; // member instantiation, uses template<>
template<typename T> struct Y { static int i; };
template<> struct Y<int> { static int i; } // template specialization
int Y<int>::i = 0; // no template<>
You don't need template anymore in the explicit function definition: void Test<int>::Problem() {printf("In Test::Problem(int instantiation)\n");}
In this case g++ gives a slightly better error message error: template-id 'Problem<>' for 'void Test<int>::Problem()' does not match any template declaration
Try this:
// The definition below gives error C2910.
void Test<int>::Problem()
{
printf("In Test::Problem(int instantiation)\n");
}
int main()
{
Test<int> hey;
hey.Problem();
return 0;
};

Can static class functions of a templated class be used without a template parameter?

I have a templated class which contains a static function which does not depend on the template parameter. Yet the compiler seems to force me to specify a typename when I use the function.
template <typename T>
class MyClass {
...
static void function();
};
template <typename T>
void MyClass<T>::function() {
....
}
This function can be used as:
MyClass<int>::function();
But the 'int' is just there to satisfy the compiler. It doesn't mean anything, and can be replaced by any other type, which doesn't increase code readability. I would like to do someting like
MyClass<>::function();
or even
MyClass::function();
but the compiler doesn't let me. I realize that this is because in the header files I have explicitly marked the function as being templated, but when I remove the '< T >' from the header file it doesn't compile either.
What is the correct way to do this?
The type is very important!
Templates can be specialized, and therefore:
template <typename T>
class MyClass {
public:
static void function() { std::cout << "Hello, World!\n"; }
};
template <>
class MyClass<City> {
public:
static void function() { launchRockets(); }
};
is a viable program.
If you then write MyClass::function(), should it annihilate Bagdad or print a friendly message ?
Of course, if there is no reason for this function to do anything else that printing, then it should perhaps be a function on its own:
void function() { std::cout << "Hello, World!\n"; }
which is invoked simply by function(), hey, it's even shorter as there is no class!
Imagine you had this:
template <typename T> struct Foo
{
static void boom()
{
static int n = 0;
std::cout << ++n << std::endl;
}
};
Now imagine what happens if you say Foo<int>::boom(); Foo<int>::boom();, and compare that to the not-at-all equivalent Foo<int>::boom(); Foo<char>::boom();.
Don't think of a template as a class. It's just a skeleton on which classes are built.
MyClass::function() doesn't have any meaning, since MyClass is not an actual class unless you specialize it.
MyClass<int>::function(); and MyClass<char>::function(); might not depend on the template parameter, they might behave the same, but they are not the same function.
Let's take a look at the binary:
MyClass<int>::function();
00D617CE call MyClass<int>::function (0D611C2h)
MyClass<char>::function();
00D617D3 call MyClass<char>::function (0D611C7h)
For this, I provided an empty definition for function, so it definitely doesn't depend on the template parameter. As you can see, the two functions are different.
That's because there are two classes there generated by the compiler - MyClass<int> and MyClass<char>.

Specialized function in non specialised Template class

Please refer to the below code
Specialized function in non specialized Template class
Is it possible to write a specialized function foo, for non specialized template class MyClass [Line Number 7] ? If yes, then, what is the syntax for the same.
Regards,
Atul
This can be done if you create a full specialization of the class template. Just refer to the answer in this question: If I want to specialise just one method in a template, how do I do it?
Otherwise if you want to have a given function with the same signature have two different behaviors depending on the instantiated version of the class, and that instantiation is a partial specialization of the template class, you will have to make a separate specialization of the template class.
Keep in mind that if you want to avoid redundant code in this second case, you can always create a base template class that will have the functionality that will not change, and then create derived template classes that will contain the unique functionality necessary for each partial specialization.
Look at my example below, I have tried answer your question (if I guessed right) in the simplest code possible by me:
#include <iostream>
using namespace std;
template<typename T>
class Some
{
public:
template<typename U> void foo(U val);
};
template<typename T>
template<typename U>
void Some<T>::foo(U val)
{
cout << "Non specialized" << endl;
}
template<>
template<>
void Some<char>::foo(char val)
{
cout << "Char specialized" << endl;
}
int main()
{
Some<int> t1;
t1.foo(5);
Some<char> t2;
t2.foo('c');
return 0;
}
The important thing to note here is that "You cannot specialize your class and function Independently" i.e you have to specialize both at the same time as done in the example.
Also, with this you lose the opportunity to specialize your class for that data type "char" in this case. (Need to confirm on this).
UPDATE :: Confirmed on point 2.
If you wanted to specialize MyClass< bool >::Foo, it would look like this:
template <>
void MyClass<bool>::Foo(bool A)
{
// code goes here
}
If you are asking that,
(1) you want a function Foo() which doesn't take any argument and
returns void inside MyClass
(2) This Foo() should be exclusive to the MyClass when the
template type is bool, i.e. only for MyClass<bool>
then here is the way:
template<class Precision>
class MyClass {
...
public:
...
void Foo (); // don't implement here
};
...
template<>
void MyClass<bool>::Foo () // implementing only for 'MyClass<bool>'
{ // invoking for other 'MyClass<>' will result in compiler error
...
}

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.