2015-12-15 15 views
5

nehme ich verwenden std::conditional bauen wollen, einen Typ zu bestimmen, wenn der Typ ein vector<...> ist die Rückkehr ein vector<...>::size_type sein wird, und wenn nicht, wird es int sein. (nur ein Beispiel).Ist es möglich, eine lazy_conditional metafunction

Eine naive Art und Weise std::conditional zu verwenden:

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; 

jedoch versagt, weil wenn C sagen ist ein double, double::size_type einen Fehler geben, auch wenn das, dass die Auswertung der zweiten falschen Option ist.

Also, ich bin frage mich, ob es eine Art lazy_conditional, in dem die falsche (oder die zweite false) Aussage wird nicht ausgewertet.

fand ich etwas hier: https://stackoverflow.com/a/5317659/225186 aber ich weiß nicht, wie es mein Beispiel zu verwenden.


Bitte beachte, dass ich weiß, wie das gleiche Ergebnis zu erhalten, ohne std::conditional mit:

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

Die Frage ist, ob es ein lazy_conditional ist, die irgendwie ein std::conditional eingekapselt, die kurzgeschlossen ist.


Nach einigen Probe Fehler schaffe ich die Ideen in https://stackoverflow.com/a/5317659/225186 zu verwenden und diese zu erhalten, die folgt. Es lässt mich auch denken, dass es nicht möglich ist, std::lazy_conditional zu schreiben, weil C::size_type überhaupt nicht in irgendeinem Ausdruck a priori erscheinen kann, also zweistufige Ausdrücke benötigt werden.

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; 

Ich konnte nicht einmal dies in ein Makro kondensieren, weil jeder Fall anders ist.

Antwort

4

Sie benötigen einen Zwischenstufe.

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; 

Der Punkt ist, bei C::size_type zu verzögern suchen (durch size_type_of<C> Instanziieren), bis Sie wissen, dass es eine hat.


Wenn das, was Sie wirklich wollen, ist „C::size_type wenn es vorhanden ist, int anders“, dann std::experimental::detected_or_t ist dein Freund:

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, und ich denke, es kann nicht als ein eingekapselt werden 'lazy_conditional '. Wie dem auch sei dies zeigt auch, dass freie metafunction als Mitglied besser sind (std :: haben size_type_of :: geben Sie nicht auf T verlassen :: size_type), wenn möglich (wie freie Funktion besser ist als Member-Funktionen für generische Code). – alfC

+0

ah, das ist etwas, was ich über entdecken und immer wieder, am Ende ist es das gleiche ich hier tat http://stackoverflow.com/questions/5839357/detect-operator-support-with-decltype-sfinae/18603716# 18603716 – alfC

+0

Auf 'detected_or_t' Kompatibilität: http://stackoverflow.com/questions/36418570/what-compiler-option-library-do-i-need-to-use-detect-or-t-type-trait?noredirect= 1 # Kommentar60486585_36418570 – alfC