Partial Template specialization definition outside of class definition - c++

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

Related

How do I define methods outside of the declaration for my specialization of a non-type template class?

The title is a mouthful, but basically I wrote something like this:
enum EnumType{ValA, ValB};
template<EnumType> class A {};
template<>
class A<ValA>
{
private:
double param;
public:
A(double param);
};
template<>
A<ValA>::A(double param)
{
// Do Stuff
}
and when I try to compile it I get:
error: template-id 'A<>' for 'A<(EnumType)0u>::A(double)' does not
match any template declaration
Am I doing this wrong?
After searching online for similar cases, I tried to remove template<> (even though I don't understand why this would work), but then I get
multiple definition of 'A<(EnumType)0u>::A(double)'
I guess that I can replace template<> by inline (I tried and it compiles), but that doesn't feel like the proper way to do it (or if it is, I don't understand why).
Can someone explain to me what is wrong with what I wrote, why changing this seems to work, and what's the proper way to do it ?
Can someone explain to me what is wrong with what I wrote, why changing this seems to work, and what's the proper way to do it ?
The standard says:
Members of an explicitly specialized class template are defined in the same manner as members of normal classes, and not using the template<> syntax.
Therefore, in your case you must use:
A<EnumType::ValA>::A(double param)
{
// Do Stuff
}
No template<> at all is just fine. That's because you are actually specializing a (special) member function (the constructor) of an explicitly specialized class template.
See it on coliru.
It would have been different if no explicit specialization was given.
As a minimal working example:
enum EnumType{ValA, ValB};
template<EnumType> class A
{
private:
double param;
public:
A(double param);
};
template<>
A<EnumType::ValA>::A(double)
{
// Do Stuff
}
int main() {
A<EnumType::ValA> a{0.};
}
In this case, template<> is required before the definition of the constructor because you are not defining a specialization of a member function of an already specialized class template.
You missed a semicolon (;) at the the end of class definition.
And the non template member function can be defined this way:
A<ValA>::A(double param) {
// Do Stuff
}
Informally, the template parameter list is only written when necessary, for example, for defining a member function template of a class template, the two template parameter list should all be written
template<class U, class V>
class A{
template <class T>
A();
};
template<class U, class V>
template <class T>
A<U, V>::A() {}
and a empty template parameter list is needed for a explicit specialisation of function template (which, i guess, is the reason why you use so here), informally because it tells the compiler that this is not a function overloading.

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

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.

Difference between member functions for a template class defined inside and outside of the class

Is there a difference between defining member functions for a template class inside the class declaration versus outside?
Defined inside:
template <typename T>
class A
{
public:
void method()
{
//...
}
};
Defined outside:
template <typename T>
class B
{
public:
void method();
};
template <typename T>
void B<T>::method()
{
//...
}
For non-template classes, this is the difference between inlined and non-inlined methods. Is this also true for template classes?
The default for most of my colleagues is to provide definitions inside the class, but I've always preferred definitions outside the class. Is my preference justified?
Edit: Please assume all the above code is provided in the header file for the class.
Yes, the exact same is true for template classes.
The reason why method definitions for template classes are usually preferred to be inline is that with templates, the entire definition must be visible when the template is instantiated.
So if you put the function definition in some separate .cpp file, you'll get a linker error.
The only general solution is to make the function inline, either by defining it inside the class or outside with the inline keyword. but in either cases, it must be visible anywhere the function is called, which means it must typically be in the same header as the class definition.
There's no difference, aside from having to type more. That includes the template bit, the inline and having to use more "elaborate" names when referring to the class. For example
template <typename T> class A {
A method(A a) {
// whatever
}
};
template <typename T> inline A<T> A<T>::method(A a) {
// whatever
}
Note that when the method is defined inside you can always omit the template parameter list <T> when referring to A<T> and just use A. When defining it outside, you have to use the "full" name in the return type and in the name of the method (but not in the parameter list).
I know this..I think it must be some what help full to u?
defining a member function outside of its template
It is not ok to provide the definition of a member function of a template class like this:
// This might be in a header file:
template <typename T>
class xyz {
void foo();
};
// ...
// This might be later on in the header file:
void xyz<T>::foo() {
// generic definition of foo()
}
This is wrong for a few reasons. So is this:
void xyz<class T>::foo() {
// generic definition of foo()
}
The proper definition needs the template keyword and the same template arguments that the class template's definition was declared with. So that gives:
template <typename T>
void xyz<T>::foo() {
// generic definition of foo()
}
Note that there are other types of template directives, such as member templates, etc., and each takes on their own form. What's important is to know which you have so you know how to write each flavor. This is so especially since the error messages of some compilers may not be clear as to what is wrong. And of course, get a good and up to date book.
If you have a nested member template within a template:
template <typename T>
struct xyz {
// ...
template <typename U>
struct abc;
// ...
};
How do you define abc outside of xyz? This does not work:
template <typename U>
struct xyz::abc<U> { // Nope
// ...
};
nor does this:
template <typename T, typename U>
struct xyz<T>::abc<U> { // Nope
// ...
};
You would have to do this:
template <typename T>
template <typename U>
struct xyz<T>::abc {
// ...
};
Note that it's ...abc not ...abc<U> because abc is a "primary" template. IOWs, this is not good:
// not allowed here:
template template struct xyz::abc { };