Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

template specialization for derived classes

I have a template class (that I cannot modify), let's call it SomeClass, that I'd like to specialize for classes that derive from a particular class only. Following this answer I was able to do this in gcc 6.3.1, but unfortunately I need to do it in gcc 4.9.2, and there it fails at compile time saying "partial specialization SomeClass<T> does not specialize any template arguments".

Is there any way I could change the below to make it work with gcc 4.9.2?

#include <iostream>
#include <string>

using namespace std;

struct A {
    string name() { return "A"; }
};

struct B : A {
    string name() { return "B"; }
};

struct C {
    string name() { return "C"; }
};

template<typename T, typename = std::enable_if_t<std::is_base_of<A, T>::value>>
using enable_if_a = T;

template<typename T>
struct SomeClass {
    using Type = T;
};

template<typename T>
struct SomeClass<enable_if_a<T>>
{
    using Type = A;
};

int main(int, char**)
{
    SomeClass<A>::Type el1;
    SomeClass<B>::Type el2;
    SomeClass<C>::Type el3;

    cout << el1.name() << "," << el2.name() << "," << el3.name() << endl;
}

Output:

A,A,C
like image 893
eddi Avatar asked Aug 14 '17 16:08

eddi


People also ask

Can templates be used for classes?

A template is not a class or a function.

Can a template base class derived?

It is possible to inherit from a template class. All the usual rules for inheritance and polymorphism apply. If we want the new, derived class to be generic it should also be a template class; and pass its template parameter along to the base class.

What is the use of template specialization?

This is called template specialization. Template allows us to define generic classes and generic functions and thus provide support for generic programming. Generic programming is an approach where generic data types are used as parameters in algorithms so that they work for variety of suitable data types.

What is explicit template specialization?

Explicit (full) specializationAllows customizing the template code for a given set of template arguments.


1 Answers

A bit contrived, but here is a machinery that at least works.
The basic idea is to hide A and do not inherit directly from it. Instead, you can heavily rely on mixins and combine a few classes in a detector with which you can specialize SomeClass.
The drawback is that classes like B become more abstruse and I'm not sure it's worth it at the end of the day. Direct specializations are probably better.

That being said, here is a working example:

#include <iostream>
#include <string>
#include <utility>

using namespace std;

class ADerivedFactory {
    struct A {
        string name() { return "A"; }
    };

    template<typename T>
    struct Detector: T { using type = A; };

public:
    template<template<typename> class C>
    using type = Detector<C<A>>;
};

template<typename T>
struct AT : T {};

template<typename T>
struct BT : T {
    string name() { return "B"; }
};

using A = ADerivedFactory::type<AT>;
using B = ADerivedFactory::type<BT>;

struct C {
    string name() { return "C"; }
};

template<typename T>
struct SomeClass {
    using Type = T;
};

template<template<typename> class C>
struct SomeClass<ADerivedFactory::type<C>>
{
    using Type = typename ADerivedFactory::type<C>::type;
};

int main(int, char**)
{
    SomeClass<A>::Type el1;
    SomeClass<B>::Type el2;
    SomeClass<C>::Type el3;

    cout << el1.name() << "," << el2.name() << "," << el3.name() << endl;
}

See it up and running on wandbox.

like image 107
skypjack Avatar answered Sep 18 '22 08:09

skypjack