2013-05-13 12 views
6

Using SFINAE to check for global operator<<?templates, decltype and non-classtypesから情報を収集、私は次のコードを得ました別の方法でto_stringメソッドを呼び出すことができます。質問1、質問2type_traitsセグメンテーションフォールト::文字列

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

から撮影

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

から撮影

その後、私のクラスはとても似ています:

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

とテスト出力:

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

print(std::string("Hi"));ラインセグフォルト。なぜ誰かが私に言うことができますか?

+2

あなたの担当者を持っている何あなたはそれを熱心に手渡しているということをあなたにしましたか? :) – jrok

+0

@jrok:私はタイプの実験を感知しています "good-but-low-repユーザはどのように扱われるのですか" ...? –

答えて

7

print()の両方の関数は何かを返すと思われますが、代わりに何も返しません(リンクされたQ &のバージョンとは異なります)。これは、C++ 11標準の段落6.6.3/2で定義されていない動作です。

print()の場合は、何も返さそれはvoidを返してみましょう、とテンプレートパラメータリストにSFINAE制約を置くことになっていません。ここで

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

は、上記の変更を含むlive exampleです。

あなたがC++ 03で作業していると、関数テンプレートパラメータのデフォルト引数を指定するだけでstd::enable_ifに2番目のテンプレート引数としてのタイプを指定しないよう、または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

2番目の既定のテンプレートパラメータで 'enable_if'を使用し、' void'を返すことでこれを修正できませんでしたか? – dyp

+0

'typename enable_if'行が戻り値であることを理解するまでにはしばらく時間がかかりました。 –

+0

@DyP:あなたは私の心を読んでいる、私はちょうど答えを編集していた;) –

関連する問題