2013-05-13 11 views
6

Raccolta di informazioni da Using SFINAE to check for global operator<<? e templates, decltype and non-classtypes, ho ottenuto il seguente codice:type_traits guasto di segmentazione con std :: string

http://ideone.com/sEQc87

Fondamentalmente ho unito il codice da entrambe le domande di chiamare print funzione se ha ostream dichiarazione, o chiamare altrimenti il ​​metodo to_string.

Tratto da domanda 1

namespace has_insertion_operator_impl { 
    typedef char no; 
    typedef char yes[2]; 

    struct any_t { 
    template<typename T> any_t(T const&); 
    }; 

    no operator<<(std::ostream const&, any_t const&); 

    yes& test(std::ostream&); 
    no test(no); 

    template<typename T> 
    struct has_insertion_operator { 
    static std::ostream &s; 
    static T const &t; 
    static bool const value = sizeof(test(s << t)) == sizeof(yes); 
    }; 
} 

template<typename T> 
struct has_insertion_operator : 
    has_insertion_operator_impl::has_insertion_operator<T> { 
}; 

Tratto da domanda 2

template <typename T> 
typename std::enable_if<has_insertion_operator<T>::value, T>::type 
print(T obj) { 
    std::cout << "from print()" << std::endl; 
} 

template <typename T> 
typename std::enable_if<!has_insertion_operator<T>::value, T>::type 
print(T obj) { 
    std::cout << obj.to_string() << std::endl; 
} 

Poi le mie classi sono in questo modo:

struct Foo 
{ 
public: 
    friend std::ostream& operator<<(std::ostream & os, Foo const& foo); 
}; 

struct Bar 
{ 
public: 
    std::string to_string() const 
    { 
     return "from to_string()"; 
    } 
}; 

E uscita di test:

int main() 
{ 
    print<Foo>(Foo()); 
    print<Bar>(Bar()); 

    //print<Bar>(Foo()); doesn't compile 
    //print<Foo>(Bar()); doesn't compile 

    print(Foo()); 
    print(Bar()); 

    print(42); 
    print('a'); 
    //print(std::string("Hi")); seg-fault 
    //print("Hey"); 
    //print({1, 2, 3}); doesn't compile 
    return 0; 
} 

I numeri di linea print(std::string("Hi"));. Qualcuno può dirmi perché?

+2

Qual è il vostro rappresentante fatto a te che lo stai distribuendo così avidamente? :) – jrok

+0

@jrok: Sto percependo un esperimento del tipo "Come si curano gli utenti di buoni-ma-bassi rappresentanti" ...? –

risposta

7

Entrambe le funzioni print() devono restituire qualcosa, ma non restituiscono nulla (diversamente dalle versioni nel Q & Come collegato). Questo è un comportamento non definito al paragrafo 6.6.3/2 dello standard C++ 11.

Se print() non deve restituire nulla, lasciarlo tornare void, e mettere il vincolo SFINAE nella lista dei parametri del modello:

template <typename T, 
    typename std::enable_if< 
     has_insertion_operator<T>::value, T>::type* = nullptr> 
void print(T obj) { 
    std::cout << "from print()" << std::endl; 
} 

template <typename T, 
    typename std::enable_if< 
     !has_insertion_operator<T>::value, T>::type* = nullptr> 
void print(T obj) { 
    std::cout << obj.to_string() << std::endl; 
} 

Ecco un live example contenente la modifica di cui sopra.

Se si lavora con C++ 03 e non è possibile specificare gli argomenti di default per i parametri di modello di funzione, basta evitare di specificare un tipo come secondo argomento modello per std::enable_if o specificare void:

template <typename T> 
typename std::enable_if<has_insertion_operator<T>::value>::type 
print(T obj) { 
    std::cout << "from print()" << std::endl; 
} 

template <typename T> 
typename std::enable_if<!has_insertion_operator<T>::value>::type 
print(T obj) { 
    std::cout << obj.to_string() << std::endl; 
} 
+0

Non è stato possibile correggere questo problema utilizzando 'enable_if' su un secondo parametro del modello predefinito e restituendo' void'? – dyp

+0

Mi ci è voluto un po 'per capire che la riga 'typename enable_if' era il valore restituito. –

+0

@DyP: Mi stai leggendo, stavo solo modificando la risposta;) –