2013-09-27 4 views
11

Während eine einfache Logger UmsetzungWarum wird ein Funktionszeiger nicht von einer universellen Referenz erfasst?

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

ich std::endl fand heraus, würde nicht durch die universal reference erfasst werden.

DebugOutput dbg; 
dgb << std::endl; 

Ich fand diese this post, die Sie hinzufügen müssen eine überladene Funktion innerhalb der Struktur, die, dh insbesondere die Funktionszeiger Unterschrift nimmt erklärt:

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

Warum die Funktionszeiger nicht erfasst wird durch die Universal Referenz ? Ist es nicht ein Typ wie int oder void*?

+0

Es ist eine Vorlage/überladen. – Xeo

+3

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

+0

mögliches Duplikat von [std :: endl ist vom unbekannten Typ beim Überladen des Operators <<] (http://stackoverflow.com/questions/1134388/stdendl-is- von-unknown-type-when-overloading-operator) – Xeo

Antwort

12

Eine Funktion (Zeiger) kann an eine universelle Referenz gebunden werden. Beispiel:

void f(int) {} 

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

foo(f); // OK 

Jedoch kann eine überladene Funktion nicht. Das heißt, wenn Sie eine zweite Überlastung von f hinzufügen, sagen wir,

void f(double) {} 

die der Anruf foo(f) fehl.

Setzen Sie sich auf die Compiler Schuhe. Es muss f an foo übergeben werden, und es gibt zwei Funktionen mit dem Namen f, von denen jede einen anderen Typ hat. Wenn wir den Typ angeben, kann der Compiler eindeutig die richtige f auswählen. Zum Beispiel

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

kompiliert fein und wird void f(int) (nach Funktion-zu-Zeiger-Umwandlung) zu foo passieren.

Allerdings informieren wir den Typ nicht. Wir bitten vielmehr den Compiler, dies abzuleiten.

ähnlich f gilt das gleiche Argument std::endl denn dies ist ein Funktions-Template ist und daher der Name std::endl stellt eine Reihe von Funktionen, die alle mit dem gleichen Namen, aber verschiedenen Typen.

Jetzt können Sie sehen, dass die Ursache des Fehlers die Tatsache ist, dass wir einen Überladungssatz bereitstellen und nach Typabzug fragen. Daher gilt dies nicht für universelle Referenzen.

std::cout << std::endl funktioniert, weil basic_ostream::operator << keine Vorlage ist und nicht versucht, den Typ des übergebenen Arguments abzuleiten. Es ist eine Funktion, die einen bestimmten Typ von std::endl übernimmt.

+0

Ziemlich klar! Danke @ cassio-neri :) –

Verwandte Themen