Reputation: 21
I am Trying to explore partial specialization of templates in order to build a traits system. Unfortunately I cannot get the full thing working. I created the simplest model to show what does not work. It is not even clear to me whether I am trying something that is not supported (actually I see around examples of the same nature but the devil is in the details).
I am just creating a small example in which I have two enums and would like to create a string differently depending on the combination of the two. Of course this is just a dummy example to show the problem, the same thing in this case can be done in many other ways.
#ifndef TESTTRAITS_H_
#define TESTTRAITS_H_
#include <string>
using namespace std;
enum MovementType {
WALKS = 0, SWIMS = 1
};
enum AnimalType {
DOG = 0, CAT = 1, DOLPHIN = 2
};
template<AnimalType A, MovementType B>
struct movementAnimal {
static const string quality;
};
template<AnimalType A>
struct movementAnimal<A,WALKS> {
static const string quality;
};
template<AnimalType A>
struct movementAnimal<A,SWIMS> {
static const string quality;
};
#endif /* TESTTRAITS_H_ */
Now I write the assignment of the static variable
#include "TestTraits.h"
template<>
const string movementAnimal<DOLPHIN, WALKS>::quality = "Not capable";
template<>
const string movementAnimal<DOLPHIN, SWIMS>::quality = "Excellent";
template<AnimalType A>
const string movementAnimal<A, SWIMS>::quality = "Decent";
template<AnimalType A>
const string movementAnimal<A, WALKS>::quality = "Very Well";
And a small main function
#include <iostream>
using namespace std;
#include "TestTraits.h"
int main() {
cout << movementAnimal<DOLPHIN,WALKS>::quality << endl;
cout << movementAnimal<DOG,WALKS>::quality << endl;
return 0;
}
If I compile I get the error:
/src/TestProject.cpp:15: undefined reference to `movementAnimal<(AnimalType)0, (MovementType)0>::quality[abi:cxx11]' collect2: error: ld returned 1 exit status>
If I remove the reference to movementAnimal<DOG,WALKS>::quality then it compiles perfectly.
I get that it is not digesting the partial template specification
template<AnimalType A>
const string movementAnimal<A, WALKS>::quality = "Very Well";
I do not know why and whether it is possible to have the pattern working.
Upvotes: 2
Views: 176
Reputation: 6594
As I can see, you put these definitions into separate files. The definition of the template classes is in TestTraits.h
, but the definition of the static consts is somewhere else. The main CPP file includes just the TestTraits.h
. That should sound like a good decision, but that doesn't work in the world of templates.
So, you have defined the enums and templates/partial specializations. Your main cpp module sees these definitions. Good. The compiler knows the template classes when it instantiates the walking dog here:
cout << movementAnimal<DOG,WALKS>::quality << endl;
Does the compiler see the definition of the static const? If it doesn't, the code like that is useless:
template<AnimalType A>
const string movementAnimal<A, WALKS>::quality = "Very Well";
When the compiler sees the code above it cannot know all the values of A
that you would use. So whenever you decide that the DOG
WALKS
, this instantiation point shall see the definition of const string movementAnimal<A, WALKS>::quality
;
The solution is to ensure that the code from main function knows both definitions of template classes and the definitions of static consts.
There are two solutions. First is to put everything into one header file or to include both files from cpp file. Don't forget to include both.
The second solution is to have an explicit instantiation of some classes somewhere in your code:
template class movementAnimal<DOG, WALKS>;
Upvotes: 4