2013-03-08 13 views
14

これで、ベクトルとその他の型にいくつかの要素をプッシュし、push_back演算子をサポートするテンプレートを作成したいと考えています。呼び出す関数がある場合はそれを無視する

私はこの

template<typename T> 
T fill(size_t n) { 
    T v; 
    //(1) 
    for(size_t i = 0; i < n; ++i){ 
     v.push_back(generate_some_how()); 
    } 
    return v; 
} 

それが動作するようにそれを行うことができます。しかし今では、(1)の代わりにv.reserve(n);を使用して、サポートするタイプの速度を向上させたいと考えています。しかし、私はまだコンパイルされないタイプのこのコードをコンパイルすることができるようにしたいreserve

これを達成するための簡単な方法はありますか?

私はハードコードされたタイプを特化するかもしれませんが、それは良いとは思われません。

C++ 11はOKです。

+0

私はそれを疑っていますが、わかりません。私の推測では、テンプレートの特殊化を使用する必要があります –

+4

あまりにも難しい....適切な署名を持つ 'reserve'メンバー関数の存在を検出する特性を書く必要があります。あなたのベルトのツールにはさまざまなアプローチがあります。 'reserve_'テンプレート関数を書いて、その特性を使って' reserve() 'やno-opを呼び出して' /(1 ) 'を使うか、ヘルパーや' fill'自体でSFINAEを使うことができます。 'fill 'のコードのほとんどが同じであるので、私はヘルパー関数を使用しようとします。 –

+0

C++ 11を使用している場合は、適切な 'emplace'呼び出しをサポートして、' push_back'を置き換えることを検討してください。 –

答えて

8

簡単な例では、C++ 11を使用して:

template<class T> 
auto maybe_reserve(T& v, size_t n, int) 
    -> decltype(v.reserve(n), void()) 
{ 
    v.reserve(n); 
} 

template<class T> 
void maybe_reserve(T&, size_t, long){} 

template<typename T> 
T fill(std::size_t n) { 
    T v; 
    maybe_reserve(v, n, 0); 
    for(size_t i = 0; i < n; ++i){ 
     v.push_back(generate_some_how()); 
    } 
    return v; 
} 

Live example.の説明については、見hereを取ります。

+0

C++ 03のバージョンも可能ですが、より複雑で拘束的です。 – Xeo

+0

'deque'の' resize'を変更した後にコンパイルされませんでした[ideone](http://ideone.com/e7p8fv) – RiaD

+0

@RiaD:これはGCC 4.7の問題です。 Clang 3.2とGCC 4.8は正しく動作します。 GCCのバグは、最初のオーバーロードの戻り値の型を 'decltype(v.reserve(n)、void()) 'に変更することで回避できます。 – Xeo

2

あまりにも難しい....適切な署名を持つ予約メンバー関数の存在を検出する特性を記述する必要があります。あなたのベルトのツールにはさまざまなアプローチがありますが、reserve()への呼び出しまたはno-opへの呼び出しにその特性を使用するreserve_テンプレート関数を記述し、// (1)から呼び出すか、ヘルパーでSFINAEを使用するか、 fillそれ自身。塗りつぶしのコードのほとんどが同じであるので、私はヘルパー関数を使用しようとします。 void reserve(std::size_t)メンバ関数は、C++ 03の中に存在している場合

は検出:

template <typename T> 
struct has_reserve { 
    typedef char yes; 
    typedef yes no[2]; 
    template <typename U, U> struct ptrmbr_to_type; 
    template <typename U> 
    static yes& test(ptrmbr_to_type<void (T::*)(std::size_t),&U::reserve>*); 
    template <typename U> static no& test(...); 
    static const bool value = sizeof(test<T>(0))==sizeof(yes); 
}; 
6

C++ 11に可能なアプローチ:ここ

template<typename T, typename = void> 
struct reserve_helper 
{ static void call(T& obj, std::size_t s) { } }; 

template<typename T> 
struct reserve_helper<T, decltype(std::declval<T>().reserve(0), void(0))> 
{ static void call(T& obj, std::size_t s) { obj.reserve(s); } }; 

template<typename T> 
T fill(std::size_t n) 
{ 
    T v; 
    reserve_helper<T>::call(v, 10); 
    for(std::size_t i = 0; i < n; ++i){ 
     v.push_back(generate_somehow()); 
    } 

    return v; 
} 

reserve()へのコールは、単に任意reserve()メンバ関数を定義していないUDTとスキップされることを示すlive exampleあります。

+0

'reserve'は' void'を返す必要があります。 – Xeo

+0

@ Xeo:すべての権利、すべての権利:編集しましょう –

+1

これをコンパイルして実行しましたか? :3 – Xeo

関連する問題