2012-06-02 25 views
6

Próbuję napisać szablonów funkcji operatora spoza UE, takich jak:W jaki sposób można użyć enable_if do wzajemnie wykluczających się szablonów funkcji nie będących członkami?

#include <utility> 

template < typename T, unsigned L > 
class MyType; 

template < typename T, typename U, unsigned L > 
auto operator ==(MyType<T,L> const &l, MyType<U,L> const &r) 
-> decltype(std::declval<T>() == std::declval<U>()) 
{ /*...*/ } 

Ale gdy próbuję obsłużyć gdy l i r mają różne długości:

template < typename T, unsigned Lt, typename U, unsigned Lu, class Enable = typename std::enable_if<(Lt < Lu)>::type > 
auto operator ==(MyType<T,Lt> const &l, MyType<U,Lu> const &r) 
-> decltype(std::declval<T>() == std::declval<U>()) 
{ /*...*/ } 

template < typename T, unsigned Lt, typename U, unsigned Lu, class Enable = typename std::enable_if<(Lt > Lu)>::type > 
auto operator ==(MyType<T,Lt> const &l, MyType<U,Lu> const &r) 
-> decltype(std::declval<T>() == std::declval<U>()) 
{ /*...*/ } 

otrzymuję błędy dwuznaczności. Próbowałem coś takiego:

które przeczytałem (tutaj na S.O.), aby rozwiązać problemy takie jak to dla szablonów funkcji członkowskich. (Czasami respondenci zmienili funkcję członka na szablon funkcji członka, aby to umożliwić). Ale błędy nie zmieniają się dla mnie. Czy muszę przełączyć się na wprowadzanie enable_if do typu zwrotu?

Och, wyrażenie typu zwrotu ma na celu wykluczenie tego operatora, gdy nie można porównać dwóch typów elementów. Czy to rzeczywiście zadziała? Czy jest on kompatybilny z umieszczaniem tam również kamery enable_if?

+1

Czym dokładnie jest błąd dwuznaczności? –

Odpowiedz

11

Interesujące jest to, że certain fellow here on SO napisał niedawno wpisany blog, pokazujący ładną technikę SFINAE w stylu C++ 11, która z łatwością pozwala na przeładowanie funkcji. Technika i objaśnienie są dostarczane here.

Podsumowując, Twój kod kończy się niepowodzeniem, ponieważ oba szablony, które są analizowane po raz pierwszy i kiedy są rozwiązywane niezależne deklaracje, są dokładnie takie same, jak w przypadku typów. Podobnie jak w przypadku domyślnych argumentów funkcji, domyślne argumenty szablonu są zastępowane tylko wtedy, gdy funkcja jest faktycznie wywoływana. To jest to, co oba szablony wyglądać do kompilatora w momencie zgłoszenia:

template<class T, unsigned Lt, class U, unsigned Lu, class Enable> 
auto operator==(MyType<T,Lt> const& l, MyType<U,Lu> const& r); 

Poniższy kod należy osiągnąć to, co chcesz:

namespace detail{ 
enum class enabler{}; 
} 

template<bool B, class T = detail::enabler> 
using EnableIf = typename std::enable_if<B, T>::type; 

template < typename T, unsigned Lt, typename U, unsigned Lu, EnableIf<(Lt < Lu)>...> 
auto operator ==(MyType<T,Lt> const &l, MyType<U,Lu> const &r) 
-> decltype(std::declval<T>() == std::declval<U>()) 
{ /*...*/ } 

template < typename T, unsigned Lt, typename U, unsigned Lu, EnableIf<(Lt > Lu)>...> 
auto operator ==(MyType<T,Lt> const &l, MyType<U,Lu> const &r) 
-> decltype(std::declval<T>() == std::declval<U>()) 
{ /*...*/ } 

Jedno pytanie pozostaje jednak ... co powinno się zdarzyć jeśli Lt == Lu? W takim przypadku żadne przeciążenie nie jest możliwe.

+0

Wow! Mój umysł został zdmuchnięty. Myślałem o wielozakresowej (dość łatwej w wariancie), ale ... łącząc tak wiele technik i kierując się takim syntaktycznym słodkim miejscem. Niesamowity. Dziękuję za udostępnienie artykułu. –

+0

Wersja 'operatora ==' w pierwszym bloku obejmuje przypadek, gdy parametry drugiego szablonu klasy są równe. Dwie wersje, o które pytam, są uzupełnieniem pierwszej wersji i nie zastępują jej. – CTMacUser

+0

To jest * bardzo * ciekawy artykuł. Dla mojego kodu użyłem 'typename std :: enable_if <(Lt < Lu)> :: type ...' jako ostatniego parametru szablonu. Mój kompilator, GCC-4.7 (32-bitowy PowerPC, z MacPorts), zaakceptował ten parametr, mimo że technicznie jest "void ..." (rodzaj niekompletny), a artykuł powiedział, że 'void' nie może być użyty! Zamierzałem użyć 'std :: nullptr_t' lub' int', ponieważ nie chciałem dodawać typu throwaway do kodu biblioteki (ale, nieważne). – CTMacUser

Powiązane problemy