2017-06-15 1 views
2

Gibt es eine einfache Möglichkeit, beide Vorlagen Spezialisierungen in eine einzige, möglicherweise mit std::enable_if, für die folgenden MWE zusammenführen?merge template specializations für const und nicht-const std :: list

#include <string> 
#include <list> 
#include <memory> 

class A { 
    // ... 
}; 
class B { 
    // ... 
}; 

template<typename T> class C {}; 

template<typename T> 
class C<std::list<T> &> : public A, public B 
{ 
    std::list<T> &l_ref; 
public: 
    C(std::list<T> &lr) : l_ref{lr} { } 
    // ... 
}; 

template<typename T> 
class C<const std::list<T> &> : public A, public B 
{ 
    const std::list<T> &l_ref; 
public: 
    C(const std::list<T> &lr) : l_ref{lr} { } 
    // ... 
}; 

Für die idiomatischen

template<typename T> 
struct C<T, typename std::enable_if< 
    std::is_same<T, std::list<E> &>::value || 
    std::is_same<T, const std::list<E> &>::value>::type> 
    : public A, public B 
{ 
    // ... 

Art und Weise, sehe ich keine Möglichkeit, E ableitbar zu machen oder die Art von "any std::list" angeben.

+0

Haben Sie meinen Sie wollen eine Vorlage schreiben, aber für beide 'const' und nicht "const" Versionen? Verhalten sie sich gleich? –

Antwort

1

Sie eine Zug erstellen können, zuerst, dann SFINAE verwenden, so etwas wie:

template <typename T> struct is_a_stdlist_ref : std::false_type {}; 
template <typename ... Ts> 
struct is_a_stdlist_ref<std::list<Ts...>&> : std::true_type {}; 
template <typename ... Ts> 
struct is_a_stdlist_ref<const std::list<Ts...>&> : std::true_type {}; 

template<typename T, typename Enabler = void> struct C; 

template<typename T> 
struct C<T, std::enable_if_t<is_a_stdlist_ref<T>::value>> 
    : public A, public B 
{ 
    //... 
}; 
+1

... was genau ist der Punkt dieses 'void_t'? –

+0

@ T.C .: in der Tat nicht benötigt, entfernt. – Jarod42

0

Gibt es eine einfache Möglichkeit, beide Vorlage Spezialisierungen zu einem einzigen zu verschmelzen, vielleicht std :: enable_if verwenden, für den folgenden MWE?

Akzeptieren Sie eine Lösung ohne std::enable_it?

Zu der Lösung flexibler zu machen, schlage ich vor, eine Art Eigenschaften zu definieren, specIndex, einen typabhängigen Index zu beheben, wo 0 „generic-Typ“ ist, 1 ist „std :: list & or const` und andere integer kann auf andere Spezialisierungen beziehen

template <typename> 
struct specIndex 
{ static constexpr std::size_t value { 0U }; }; // generic version 

template <typename T> 
struct specIndex<std::list<T> &> 
{ static constexpr std::size_t value { 1U }; }; // pro lists 

template <typename T> 
struct specIndex<std::list<T> const &> 
{ static constexpr std::size_t value { 1U }; }; // pro lists 

Der nächste Schritt ist ein Parameter Standardvorlage integer hinzu C

template <typename T, std::size_t = specIndex<T>::value> 
class C 
{ }; 

Die l ast Schritt ist, den Index 1 (std::list<T> & oder konstant) Spezialisierung zu definieren

template<typename T> 
class C<T, 1U> : public A, public B 
{ 
    private: 
     T & l_ref; 

    public: 
     C (T & lr) : l_ref{lr} 
     { std::cout << "- list version" << std::endl; } 
}; 

Das Folgende ist ein vollständiges Beispiel

#include <string> 
#include <list> 
#include <memory> 
#include <iostream> 

class A 
{ }; 

class B 
{ }; 

template <typename> 
struct specIndex 
{ static constexpr std::size_t value { 0U }; }; // generic version 

template <typename T> 
struct specIndex<std::list<T> &> 
{ static constexpr std::size_t value { 1U }; }; // pro lists 

template <typename T> 
struct specIndex<std::list<T> const &> 
{ static constexpr std::size_t value { 1U }; }; // pro lists 

template <typename T, std::size_t = specIndex<T>::value> 
class C 
{ }; 

template<typename T> 
class C<T, 1U> : public A, public B 
{ 
    private: 
     T & l_ref; 

    public: 
     C (T & lr) : l_ref{lr} 
     { std::cout << "- list version" << std::endl; } 
}; 

int main() 
{ 
    std::list<long> sll; 

    C<int>      a; 
    C<std::list<long> &>  b{sll}; 
    C<std::list<long> const &> c{sll}; 
} 
Verwandte Themen