2017-08-14 93 views
13

Bir şablon sınıfım var (değiştiremediğim), SomeClass diyelim, sadece belirli bir sınıftan türeyen sınıflar için uzmanlaşmak istiyorum. this answer sonra bunu gcc 6.3.1, ancak maalesef gcc 4.9.2 içinde yapmak gerekiyordu ve orada "kısmi uzmanlık SomeClass<T> herhangi bir şablon argümanları" uzmanlık yok söyleyerek orada başarısız.şablon uzmanlığı

Gcc 4.9.2 ile çalışmasını sağlamak için aşağıdakileri değiştirebileceğim bir yol var mı?

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

Çıktı:

A,A,C 
+0

@AndyG Uzmanlaşmamış olsaydım "A, B, C" alırdım. A ve B için uzmanlık istiyorum. – eddi

+1

Bunun bir kopyası gibi görünüyor: https://stackoverflow.com/questions/12858839/using-sfinae-for-template-class-specialisation Eğer çift değilse o zaman yakın bir akrabası ve cevabınız muhtemelen ... gcc 4.9.2 ve OP'de belirtildiği gibi tüm –

+0

@Drt - bu soru benim başlangıç ​​noktamdı - ihtiyaçlarım için nasıl uyarlayacağımı bilmiyorum. Şu anki girişimim 4.9.2 ile çalışmıyor. – eddi

cevap

3

Biraz yapmacık, ama burada en az çalışan bir makine olduğunu.
Temel fikir, A belgesini gizler ve doğrudan ondan devralmaz. Bunun yerine, miksleri ağır bir şekilde kullanıp, SomeClass'u uzmanlaşabileceğiniz bir detektördeki birkaç sınıfı birleştirebilirsiniz.
Bu dezavantajı, B gibi sınıfların daha berbat olması ve günün sonunda buna değdiğinden emin değilim. Doğrudan uzmanlaşmalar muhtemelen daha iyi.

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

o kadar görmek ve wandbox üzerinde çalışan: söyleniyor

, burada çalışan bir örnektir.

+0

Teşekkürler, bu ilginç. Sınıf A'yı değiştirmek için erişimim var, ama eminim ki bunu yapmak için öldürüyüm :) Bu eğitimsel bir yaklaşım olsa da. – eddi

+1

@eddi Şey, dediğim gibi, işe yarıyor. Bu tek avantaj. Güzellik başka bir şey değil. :-D – skypjack