Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 520
djgandy Avatar asked Jan 07 '23 19:01

djgandy


2 Answers

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 image 168
Useless Avatar answered Jan 31 '23 09:01

Useless


Like this works:

// template <>
void A<AnimalType::Cat>::meow()
{
}

As you are defining a member function of the concrete class A<AnimalType::Cat>.

like image 39
marom Avatar answered Jan 31 '23 08:01

marom