Подтвердить что ты не робот

Типовая специализация для производных классов

У меня есть класс шаблона (который я не могу изменить), позвоните ему SomeClass, который я хотел бы специализировать для классов, которые производятся только из определенного класса. Следуя этому ответу, я смог сделать это в gcc 6.3.1, но, к сожалению, мне нужно сделать это в gcc 4.9.2, и там он не работает во время компиляции "частичная специализация SomeClass<T> не специализирует никаких шаблонных аргументов".

Есть ли способ изменить нижеследующее, чтобы он работал с 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;
}

Вывод:

A,A,C
4b9b3361

Ответ 1

Немного изобретенный, но вот механизм, который, по крайней мере, работает.
Основная идея - скрыть A и не наследовать напрямую от него. Вместо этого вы можете в значительной степени полагаться на mixins и объединить несколько классов в детекторе, с помощью которого вы можете специализироваться SomeClass.
Недостатком является то, что классы, подобные B, становятся более заумными, и я не уверен, что это стоит в конце дня. Прямые специализации, вероятно, лучше.

Как говорится, вот рабочий пример:

#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;
}

Посмотрите и запустите wandbox.