2014-02-12 8 views
6

Ich verstehe den Inhalt von this question aber wie funktioniert es, wenn Funktionsüberlastungen verwendet werden?Wie weiß das Schlüsselwort 'auto', wann eine Überladungsfunktion für Konstanten verwendet werden muss?

Zum Beispiel in std::map die folgenden Methoden definiert:

 iterator find (const key_type& k); 
const_iterator find (const key_type& k) const; 

Wie ist es möglich, die eine oder andere mit dem auto Schlüsselwort zu holen? So etwas wie die folgenden scheint nicht richtig zu mir:

auto i = mymap.find(key);  //calls the non-const method? 
const auto i = mymap.find(key); //calls the const method? 
+0

Das ist zu spät ist, die LHS ist nicht an der Überladungsauflösung beteiligt. –

+0

@MarcGlisse Willst du damit sagen, dass es nicht funktioniert mit 'const_iterator i = mymap.find (key);'? Also, was ist der Sinn dieser Funktionsüberlastung? – DarioP

+0

'auto it = as_const (Karte) .find (...);' – Xeo

Antwort

3
std::map<int, int> mutable_map; 
const std::map<int, int> const_map; 

mutable_map.find(1); // returns iterator 
const_map.find(1); // returns const_iterator 

Sie würden nicht regelmäßig Iterator von einer konstanten map zurückkehren wollen, weil das die Konstantheit untergraben würde. Die einzige Möglichkeit, eine find Member-Funktion zu haben, die vernünftig mit der Konstante maps arbeitet, ist eine const Überladung, die eine const_iterator zurückgibt.

+0

Der Punkt ist, dass Sie vielleicht einen 'const_iterator' mit einer veränderbaren Map möchten. Also die Möglichkeiten sind die implizite Konvertierung oder die Funktion: 'template consExpr const T & as_const (T & t) {return t; } 'verwendet, um während der Kompilierzeit eine Konstante const zu erhalten, die den Const_iterator zurückgibt. – DarioP

1

In C++ 14 haben Sie cbegin und cend, um einen Const_iterator Getter zu erzwingen.

Um dasselbe mit den Suchmethoden der Karte zu tun, brauchen Sie const_cast, aber die Syntax ist schrecklich oder ein kleiner Helfer.

#include <iostream> 
#include <map> 

template <typename T> T const & ccast(T const & v) { return v; } 
template <typename T> T const && ccast(T const && v) { return v; } 

int main() { 
    using Map = std::map<int,int>; 
    Map map; 

    static_assert(std::is_same< decltype(map.find(1)), Map::iterator >::value, " mutable map give mutable iterator"); 
    static_assert(std::is_same< decltype(const_cast<Map const&>(map).find(1)), Map::const_iterator >::value, "const map give imutable iterator"); 

    static_assert(std::is_same< decltype(ccast(map).find(1)), Map::const_iterator >::value, "const map give imutable iterator"); 
    static_assert(std::is_same< decltype(ccast(std::move(map)).find(1)), Map::const_iterator >::value, "const map give imutable iterator"); 
} 

Aber für eine Karte, die wandelbar Fund aufrufen und speichern als const iterator bei der Zuordnung der einfachste ist zu beachten, dass es von ihm Iterieren verhindern wird nach diesem

auto const it = map.find(1); 
it++ // compilation error 
std::for_each(it, end(map), /**/); // compilation error too 
+0

Ich habe bereits cbegin und cend sogar in C++ 11 verwendet, vielleicht sind sie nur Aliase. Es sieht so aus, als würden Sie es viel zu kompliziert machen. Sobald Sie Ihre '& ccast' definiert haben, können Sie einfach' auto it = ccast (map) .find (...); 'verwenden. Die rvalue-Referenz scheint in diesem Fall nutzlos. Wenn Sie schließlich 'auto const it = map.find (1);' aufrufen, erhalten Sie keinen 'const_iterator' (der den Wert des Elements nicht ändern kann), sondern einen 'const iterator' (der das angegebene Element nicht ändern kann). – DarioP

+0

@DarioP Die Rvalue-Referenzversion ist der Vollständigkeit halber, sie ändert das Ergebnis hier nicht, aber bei einem Objekt mit Methodenüberladung basierend auf dem Referenztyp ist es wichtig. 'struct A {int foo() &; int foo() &&; } '. – galop1n

+0

@DarioP Und war nur Tagträumen auf dem Zauberstab const_iterator ... – galop1n