2013-09-27 6 views
11

汎用ポインタが汎用参照によってキャプチャされないのはなぜですか?

struct DebugOutput { 
    DebugOutput(std::ostream& out = std::cerr) : m_Out(out) {} 

    template<typename T> 
    inline DebugOutput& operator <<(T&& value) { 
     m_Out << value; 
     return *this; 
    } 
private: 
    std::ostream& m_Out; 
}; 

シンプルなロガーを実装している間、私はstd::endluniversal referenceによって捕獲されないが分かりました。

DebugOutput dbg; 
dgb << std::endl; 

は、私が説明し、この this postはあなたが特に関数ポインタの署名を取る構造、すなわち内オーバーロードされた関数を追加する必要がありますが見つかりました:関数ポインタが普遍的で捕捉されていないのはなぜ

typedef std::ostream& (*StandardEndLine)(std::ostream&); 
inline DebugOutput& operator<<(StandardEndLine manip) { 
    return *this; 
} 

参照 ?それはintまたはvoid*のようなタイプではありませんか?

+0

テンプレート/オーバーロードです。 – Xeo

+3

http://stackoverflow.com/a/1136617/46642 –

+0

[std :: endlが重複している可能性があります。演算子<<をオーバーロードすると型が不明です(http://stackoverflow.com/questions/1134388/stdendl-is- of-unknown-type-when-overloading-operator) – Xeo

答えて

12

関数(ポインタ)を汎用参照にバインドすることができます。例:

void f(int) {} 

template <typename T> 
void foo(T&&) {} 

foo(f); // OK 

ただし、オーバーロードされた関数はできません。あなたがfの2番目のオーバーロードを追加する場合には、コールfoo(f)が失敗します

void f(double) {} 

、たとえば、あります。

コンパイラの靴を身に着けてください。 ffooに渡す必要があり、それぞれが異なるタイプのfという2つの関数があります。タイプを通知すると、コンパイラは正しいfを明白に選択できます。例えば、

foo(static_cast<void (*)(int)>(f)); 

微細コンパイルしfooに(関数へのポインタ変換後)void f(int)を通過します。

しかし、私たちはタイプを知らせていません。むしろ、コンパイラに推論するように依頼しています。

fと同様に、同じ引数がstd::endlに適用されます。これは関数テンプレートであるため、std::endlという名前はすべて同じ名前ですが異なる型の関数群を表します。

ここでは、エラーの原因は、オーバーロードセットを提供し、タイプ控除を求めるということです。したがって、これは普遍的な参照に特定ではない。

std::cout << std::endlbasic_ostream::operator <<はテンプレートではなく、渡された引数の型を推測しようとしないために機能します。これは、ある特定のタイプのstd::endlをとる関数です。

+0

かなりクリア!ありがとう@ cassio-neri :) –

関連する問題