2016-05-09 6 views
1

私はライブラリを作成しています。オブジェクトを文字列にする必要があります。テンプレート型のオーバーロード解決と演算子<<に関する問題

私はoperator<<(ostream&...をサポートすることを選択しました。

もう1つは、{?}フォームにoperator<<(ostream&...のない型のデフォルト文字列を提供する必要があることです。

vector<>のようなテンプレート型で問題があります。ユーザーがvector<int>vector<float>の2つのオーバーロードを書いて欲しくないですが、動作させることができません。

#include <string> 
#include <type_traits> 
#include <sstream> 
#include <vector> 
#include <iostream> 
using namespace std; 

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

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

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

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

    template <typename T> 
    struct has_insertion_operator { 
     static 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> {}; 

template <class T> 
typename enable_if<has_insertion_operator<T>::value, string>::type stringify(const T& in) { 
    stringstream stream; 
    stream << in; 
    return stream.str(); 
} 

template <class T> // note the negation here compared to the one above 
typename enable_if< ! has_insertion_operator<T>::value, string>::type stringify(const T&) { 
    return "{?}"; 
} 

// USER CODE: 

struct myType {}; 

ostream& operator<<(ostream& s, const myType&) { s << "myType"; return s; } 

template<typename T> 
ostream& operator<<(ostream& s, const vector<T>&) { s << "vector<T>"; return s; } 

int main() { 
    myType a;   cout << stringify(a) << endl; // prints "myType" 
         cout << stringify(6) << endl; // prints "6" 
    vector<int> v(5); cout << stringify(v) << endl; // prints "{?}" instead of "vector<T>" 

    return 0; 
} 

myTypeと整数文字列化しかしvector<int>のために、私はデフォルト{?}をゲット両方:ここ

はコードです。

私はこれに助けが必要です - それは私のためのshowstopperです。私はユーザーが用意したoperator<<(ostream&...のオーバーロードを修正せずにすぐに動作させる必要があります。これはすべてC++ 98で行います。

+1

_ "私のヘッダーでは何もドラッグしないでください。またはさらに" _ Twofold:1. [フォワード宣言](http://stackoverflow.com/questions/625799/resolve-header-include-circular依存関係)2. [テンプレート実装](http://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file)それはちょっとしたばかげた制限かもしれません、どうしてあなたはその理由を明確にすることができますか? –

+0

[mcve]を入力してください。最小限の強調。あなたが見ている問題を再現するために、3つのファイルに140行のコードを分散させる必要はありません。 – Barry

+1

また、すべての 'std'型を手作業でフォワードするには' 'が好きです。それがそのヘッダーの存在の目的です。 – Barry

答えて

0

の第二のペアは私がしなければならなかったすべては挿入演算子形質の実装で名前空間を削除して判明一致しますフォールバックoperator<<(ostream&...は、グローバルスコープで終了します - hereを説明しています。

1

これは次のようになりますが、C++ 11のためにあなたのstringize機能

のためのより良い候補者を提供する必要がベクトルを一致させるには:

template <template <typename...> class V, typename... Args> 
typename enable_if< !has_insertion_operator<V<Args...>>::value, string>::type stringify(const V<Args...>&) { 
    return "template {?}"; 
} 
// also add enable_if for yes with code identical to the one in template<typename T> 

あなたがC++ 98を必要とするので、私は怖いですあなたは1からN(例えば5または10)のargsのためにいくつかのテンプレートオーバーロードを提供する必要があります。このような。たとえばvectorについては

template <template <typename> class V, typename T0> 
... 
template <template <typename, typename> class V, typename T0, typename T1> 
... 
/// etc 

あなたのケースでは2つのテンプレート引数を持っており、yes/no機能

関連する問題