2010-12-06 13 views
5

Ich habe eine Trait-Klasse, die ich oft spezialisieren (und teilweise spezialisieren) muss.Mehrdeutige partielle Template-Spezialisierung

Einige Teil Spezialisierungen überlappen:

template< typename T > struct C { }; 
template< typename T1, typename T2 > struct TRAIT { }; 

template< typename T > struct TRAIT< T, T > { }; 
template< typename T1, typename T2 > struct TRAIT< C<T1>, C<T2> > { }; 

int main() { 
    // ERROR! could be both TRAIT<T,T> [with T = C<int>] 
    //     and TRAIT<T1,T2> [with T1 = T2 = int] 
    TRAIT< C<int>, C<int> > foo; 
    return 0; 
}; 

Wie soll ich das gleiche Ergebnis mit einem funktionierenden Code bekommen?

Ich ging verrückt mit enable_if und is_same, ich bin nicht einmal mehr sicher, es ist der richtige Weg ...

+2

Was versuchst du wirklich? –

+2

Sie sollten Überschneidungen vermeiden. Das ist die Antwort. Die Frage ist die von Karl gestellte Frage: Was versuchst du wirklich? –

+0

Es tut mir leid, Kumpel, aber Sie verwenden C++ falsch. Überdenken Sie Ihre Lösung und/oder schreiben Sie das eigentliche Problem auf, um eine tatsächliche Antwort zu erhalten. – Squirrelsama

Antwort

6

Ihre beste Wette für diese, wenn Sie sich nicht überlappende Spezialisierung vermeiden kann, ist alles zu klären, Ihre Überschneidungen. Sie werden eine weitere Spezialisierung für

template< typename T> struct TRAIT< C<T>, C<T> > { }; 

schreiben müssen ... aber, wie alle anderen in den Kommentaren gesagt, ist es am besten Überschneidungen zu vermeiden, wenn überhaupt möglich. Wie andere bereits erwähnt haben, kann es sein, dass sich das Problem nicht mit Spezialisierungen überschneidet. Möglicherweise ist dies nicht der beste Ansatz, um Ihr Problem zu lösen.

+0

Ich weiß nicht, wie ich tun kann, was ich brauche (was ich geschrieben habe in einem Kommentar zu der Frage), und dies scheint die beste Methode, um es zu erreichen – peoro

0

Versuchen:

template< typename T > struct C { }; 
template< typename T1, typename T2 = T1> struct TRAIT { }; 
           // ^^^^^^^^^ 
           // Default Type is T1 

int main() 
{ 
     TRAIT<C<int> >   foo1; 
     TRAIT<C<int>, C<int> > foo2; 

     foo1 = foo2; 
     return 0; 
}; 
+0

Ich bin mir nicht sicher, es würde funktionieren, die OP wird wahrscheinlich immer die beiden Parameter übergeben, denn es scheint wie das Ziel der Traits-Klasse zu erkennen, ob die Typen gleich sind. –

0

Der Trick ist, ein Helfer-Typ zu schaffen, der Ihnen sagt, wenn etwas ein C<Foo> ist oder nicht:

template <typename T> struct C {}; 

template <typename T> struct is_C { 
    static bool const value = false; 
}; 
template <typename T> struct is_C<C<T>> { 
    static bool const value = true; 
}; 

Sie mit enable_if auf dem richtigen Weg waren, aber is_same scheint eine Sackgasse sein:

#include <type_traits> 

template <typename T1, typename T2, typename Enabled = void> struct Trait { 
    static char const test = 'D'; // default 
}; 

template <typename T> struct Trait< 
    T, 
    T, 
    typename std::enable_if<!is_C<T>::value >::type 
> { 
    static char const test = 'N'; // non-C 
}; 

template <typename T1, typename T2> struct Trait< 
    T1, 
    T2, 
    typename std::enable_if< is_C<T1>::value && is_C<T2>::value >::type 
> { 
    static char const test = 'C'; // some C 
}; 

Welche? Sie können ganz einfach jetzt testen:

#include <iostream> 

int main() { 
    Trait< C<int>, C<float> > foo1a; 
    Trait< C<int>, C<int> > foo1b; 
    Trait< int, int > foo2; 
    Trait< int, float > foo3; 
    std::cout << "Trait<C<int>,C<float>> : " << foo1a.test << std::endl; // prints 'C' 
    std::cout << "Trait<C<int>,C<int>> : " << foo1b.test << std::endl; // prints 'C' 
    std::cout << "Trait<int,int> : " << foo2.test << std::endl; // prints 'N' 
    std::cout << "Trait<int,float> : " << foo3.test << std::endl; // prints 'D' 
    return 0; 
} 

Sie können ganz einfach das ändern, wenn Sie Ihre Spezialisierung wollen nur mit einem der Parameter zu arbeiten, ein C oder was auch immer Sie zu sein.