2013-08-08 4 views
27

Ich versuche zu verstehen std::reference_wrapper.Wie richtig zu verwenden std :: reference_wrappers

Der folgende Code zeigt, dass sich der Referenzwrapper nicht genau wie eine Referenz verhält.

#include <iostream> 
#include <vector> 
#include <functional> 

int main() 
{ 
    std::vector<int> numbers = {1, 3, 0, -8, 5, 3, 1}; 

    auto referenceWrapper = std::ref(numbers); 
    std::vector<int>& reference = numbers; 

    std::cout << reference[3]    << std::endl; 
    std::cout << referenceWrapper.get()[3] << std::endl; 
       // I need to use get^
       // otherwise does not compile. 
    return 0; 
} 

Wenn ich es richtig verstehe, gilt die implizite Konvertierung nicht für aufrufende Member-Funktionen. Ist das eine inhärente Einschränkung? Muss ich die std::reference_wrapper::get so oft benutzen?

Ein anderer Fall ist dies:

#include <iostream> 
#include <functional> 

int main() 
{ 
    int a = 3; 
    int b = 4; 
    auto refa = std::ref(a); 
    auto refb = std::ref(b); 
    if (refa < refb) 
     std::cout << "success" << std::endl; 

    return 0; 
} 

Dies funktioniert gut, aber wenn ich diese über der main Definition hinzufügen:

template <typename T> 
bool operator < (T left, T right) 
{ 
    return left.someMember(); 
} 

Der Compiler versucht, die Vorlage und vergisst über implizite Konvertierung zu instanziiert und der eingebaute Operator.

Ist dieses Verhalten inhärent oder missverstehe ich etwas Entscheidendes über die std::reference_wrapper?

+3

'std :: reference_wrapper' hat einige sehr spezielle Verwendungen für Bibliotheksautoren, die relevant sind für die perfekte Weiterleitung und Speicherung von Argumenten (siehe z.B.' std :: bind' und 'std :: thread'). Ich empfehle es nicht außerhalb dieser Situationen zu verwenden. – Xeo

+8

'reference_wrapper' ist kein Ersatz für Referenzen. –

+2

'Vorlage Bool-Operator <(T links, T rechts) { return left.someMember(); } ist ein Beispiel dafür, was NIEMALS NIEMALS TUN WURDE, wenn ein Bediener überlastet wird. Alle Probleme, die aufgrund dieses Codes auftreten, sind nicht das Problem von irgendetwas anderem in Ihrer Codebasis. (ok, vielleicht in einem lächerlich eingeschränkten und kontrollierten 'Namespace', der über ADL gefunden werden kann, oder ähnlich konstruierte Situationen) – Yakk

Antwort

28

std::reference_wrapper<T> Klasse implementiert einen impliziten Operator Umwandlung zu T&:

operator T&() const noexcept; 

und einem expliziten Getter:

T& get() const noexcept; 

Der implizite Bediener aufgerufen wird, wenn ein T (oder T&) erforderlich ist. Zum Beispiel

void f(some_type x); 
// ... 
std::reference_wrapper<some_type> x; 
some_type y = x; // the implicit operator is called 
f(x);   // the implicit operator is called and the result goes to f. 

jedoch manchmal ein T ist nicht unbedingt zu erwarten, und in diesem Fall müssen Sie get verwenden. Dies geschieht hauptsächlich in automatischen Typabzugskontexten. Zum Beispiel

template <typename U> 
g(U x); 
// ... 
std::reference_wrapper<some_type> x; 
auto y = x; // the type of y is std::reference_wrapper<some_type> 
g(x);  // U = std::reference_wrapper<some_type> 

Um some_type statt std::reference_wrapper<some_type> oben sollten Sie oben

auto y = x.get(); // the type of y is some_type 
g(x.get());  // U = some_type 

Alternativelly die letzte Zeile tun konnte durch g<some_type>(x); ersetzt werden. Allerdings, für templatized Operatoren (z. B. ostream::operator <<()) Ich glaube, dass Sie den Typ nicht explizit angeben können.

+0

Es scheint nicht explizit zu sein: http: //en.cppreference.com/w/cpp/utility/funktional/reference_wrapper/get – xaxxon

+0

@xaxxon: Es war ein Tippfehler und ich meinte "implizit". Ich habe die Post repariert. Vielen Dank. –

Verwandte Themen