2013-05-13 17 views
6

Zbieranie informacji z Using SFINAE to check for global operator<<? i templates, decltype and non-classtypes, mam następujący kod:type_traits błędów segmentacji z std :: string

http://ideone.com/sEQc87

Zasadniczo połączeniu kod z obu pytań zadzwonić print funkcję, jeśli ma ostream deklaracji lub w inny sposób wywołać metodę to_string.

Zrobione z pytaniem 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> { 
}; 

Zrobione z pytaniem 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; 
} 

Wtedy moje zajęcia są tak:

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()"; 
    } 
}; 

i wyjście testu:

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

Uszkodzenia linii print(std::string("Hi"));. Czy ktoś może mi powiedzieć dlaczego.

+2

Co ma swoją rep zrobione tobie, że tak chętnie to rozdajesz? :) – jrok

+0

@jrok: Wyczuwam eksperyment typu "Jak dobrze traktowani użytkownicy są traktowani" ...? –

Odpowiedz

7

Obie twoje funkcje, print(), mają zwrócić coś, ale nic nie zwracają (w przeciwieństwie do wersji w Q & w trakcie łączenia). Jest to niezdefiniowane zachowanie według paragrafu 6.6.3/2 normy C++ 11.

Jeśli print() nie ma powrócić niczego, niech powróci void i umieścić ograniczenie SFINAE na liście parametrów szablonu:

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

Oto live example zawierający powyższą zmianę.

Jeśli pracujesz z C++ 03 i nie można określić domyślne argumenty parametrów szablonu funkcji, po prostu unikać, określając typ jako drugi szablonu argumentu std::enable_if lub określić 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

Nie można tego naprawić, używając 'enable_if' na drugim, domyślnym parametrze szablonu i zwracając' void'? – dyp

+0

Zajęło mi trochę czasu, zanim zorientowałem się, że wiersz 'typename enable_if' był wartością zwracaną. –

+0

@DyP: Czytasz mój umysł, właśnie edytowałem odpowiedź;) –