2015-12-15 11 views
5

Załóżmy, że chcę użyć std::conditional do określenia typu, jeśli typ to vector<...>, zwrot będzie wynosił vector<...>::size_type, a jeśli nie, to będzie to int. (tylko przykład).Czy jest możliwe zbudowanie metafunkcji lazy_neond_inne

naiwny sposób na wykorzystanie std::conditional:

template<class V> struct is_vector : std::false_type{}; 
template<class T> struct is_vector<std::vector<T>> : std::true_type{}; 

template<class C> 
using my_size_type = typename std::conditional< 
    not is_vector<C>::value, 
    int, 
    C::size_type // note that this line only makes sense when condition is false 
>::type; 

Jednak to się nie powiedzie, ponieważ jeśli C jest powiedzieć double, double::size_type daje błąd, nawet jeśli to jest ocena drugiego fałszywego opcji.

Zastanawiam się, czy istnieje coś w rodzaju lazy_conditional, w którym fałszywe (lub drugie fałszywe) stwierdzenie nie jest oceniane.

Znalazłem coś tutaj: https://stackoverflow.com/a/5317659/225186, ale nie wiem, jak z niego korzystać, mój przykład.


Zauważ, że wiem, jak uzyskać ten sam efekt bez użycia std::conditional:

template<class V> struct my_size_type{typedef int type;}; 
template<class T> struct my_size_type<std::vector<T>>{typedef std::vector<T>::size_type type;}; 

Pytanie brzmi, czy istnieje lazy_conditional że jakoś obudowane jest std::conditional że jest zwarcie.


Po pewnym błędem próby udaje mi się korzystać z pomysłów w https://stackoverflow.com/a/5317659/225186 i dostać się do tego, że następuje. To również sprawia, że ​​myślę, że nie można napisać std::lazy_conditional, ponieważ C::size_type nie może pojawić się w ogóle w żadnym wyrażeniu a priori, więc potrzebne są dwuetapowe wyrażenia.

template<class C, bool B> struct false_case{ 
    typedef void type; 
}; 
template<class C> struct false_case<C, false>{ 
    typedef typename C::size_type type; 
}; 

template<class C> 
using size_type = typename std::conditional< 
    not is_vector<C>::value, 
    int, 
    typename false_case<C, not is_vector<C>::value>::type 
>::type; 

Nie mogłem nawet skondensować tego w makrze, ponieważ każdy przypadek jest inny.

Odpowiedz

4

Potrzebujesz poziomu pośredniego.

template<class T> struct identity { using type = T; }; 

template<class C> 
struct size_type_of : identity<typename C::size_type> { }; 

template<class C> 
using size_type = typename std::conditional<not is_vector<C>::value, 
              identity<int>, 
              size_type_of<C>>::type::type; 

Chodzi o to, aby opóźnić patrząc na C::size_type (o uruchamianiu size_type_of<C>), dopóki nie wie, że ma.


Jeśli to, co naprawdę chcesz robić to "C::size_type jeśli istnieje, int inaczej", a następnie std::experimental::detected_or_t jest twoim przyjacielem:

template<class C> 
using size_type_t = typename C::size_type; 

template<class C> 
using size_type_or_default = std::experimental::detected_or_t<int, size_type_t, C>; 
+0

Ok, i myślę, że to nie może być zamknięty jako 'lazy_conditional '. W każdym razie pokazuje to również, że wolna metafunkcja jest lepsza niż członek (ma std :: size_type_of :: type zamiast polegać na T :: size_type), kiedy jest to możliwe (jak funkcja wolna jest lepsza niż funkcje członkowskie dla kodu ogólnego). – alfC

+0

ah, to jest coś, co odkrywam w kółko, na końcu jest tak samo jak tutaj: http://stackoverflow.com/questions/5839357/detect-operator-support-with-decltype-sfinae/18603716# 18603716 – alfC

+0

Na temat zgodności "detected_or_t": http://stackoverflow.com/questions/36418570/what-compiler-option-library-do-i-need-to-using-detect-or-t-type-trait?noredirect= 1 # comment60486585_36418570 – alfC

Powiązane problemy