2016-08-03 16 views
0

Update dank AlexD Antwort: Diese Frage läuft darauf hinaus, die Sprachregeln für die Mitgliedsfunktion Überlastungen der Auswahl, die in den folgenden Fragen diskutiert: Calling a const function rather than its non-const versionBereich Expression von bereichsbasierten for-Schleifen konstante Funktion verwenden Überlastungen


Wenn der Bereich Expression eines range-based for loop ist ein Aufruf an eine Elementfunktion mit const und nicht const Überlastungen, so scheint es, dass die nicht-const Überlast ausgewählt wird. Als Ergebnis wird das folgende Programm nicht kompilieren:

#include <iostream> 
#include <vector> 

class foo { 
    public: 
     const std::vector<int>& get_numbers() const { return numbers; } 
    protected: 
     std::vector<int>& get_numbers() { return numbers; } 
    private: 
     std::vector<int> numbers; 
}; 

int main() { 
    foo f; 
    for (int x : f.get_numbers()) std::cout << x << std::endl; 
} 

Diagnosemeldung von gcc 5.3:

error: ‘std::vector<int>& foo::get_numbers()’ is protected

Aber eine const Version von get_numbers() ist verfügbar und könnte verwendet werden. Wir können sie zwingen, durch die Verwendung eines const Verweis auf die foo Instanz verwendet werden soll, wie folgt aus:

int main() { 
    foo f; 
    const foo& g = f; 
    for (int x : g.get_numbers()) std::cout << x << std::endl; 
} 

Gibt es eine bessere/einfachere Möglichkeit, den Compiler zu sagen, dass er kann und die const Memberfunktion Überlastung verwendet werden soll, ohne explizit eine const Referenz auf das Objekt zu machen?

Es gibt einige similar questions über die bereichsbasierte for-Schleife Gebrauch machen const Iteratoren, aber ich habe keine Fragen zu machen die Schleife des Bereichsausdruck const für die Zwecke der Auswahl der Funktion Überlastungen gefunden.

+0

Ich glaube, das als 'foo f erklärt wegen' f' geschieht, 'und nicht' const foo f; 'Deshalb ist die nicht-const überladene Funktion über const gewählt wird. Meine Frage ist, warum brauchen Sie die 'getNumbers()' sowohl öffentliche als auch private? – DimChtz

+0

Vermeiden Sie private/geschützte Getter/Setter (oder verwenden Sie einen anderen Namen) –

+0

@DimChtz Ja, das ist das Problem.Die ausgewählte Überladung ist die Funktionssignatur, nicht der Rückgabetyp. – doug

Antwort

3

Aber eine const Version von get_numbers() ist verfügbar und könnte verwendet werden.

Die beste Funktion wird ausgewählt, bevor die Barrierefreiheit berücksichtigt wird. Die Standardzustände (Hervorhebung von mir):

Wenn eine beste realisierbare Funktion existiert und einzigartig ist, ist die Überladungsauflösung erfolgreich und erzeugt sie als Ergebnis. Andernfalls schlägt die Überladungsauflösung fehl und der Aufruf ist fehlerhaft. Wenn die Überladungsauflösung erfolgreich ist, und die beste realisierbare Funktion nicht zugänglich ist (Abschnitt 11) in dem Kontext, in dem es verwendet wird, ist das Programm schlecht gebildet.

+0

Danke, das ist eine gute Information, soweit das Verständnis, warum die Nicht-'const' Überladung ausgewählt ist. Aber es beantwortet nicht ganz die Frage, ob es einen bequemeren Weg gibt, die 'const'-Überladung auszuwählen, ohne explizit einen' const'-Verweis auf die Instanz zu machen. – TypeIA

+0

@TypeIA Einige andere schlagen das gleiche wie Sie vor: http://StackOverflow.com/a/7287093 – AlexD

+0

Danke, das ist ein guter Link und ich habe es oben auf meine Frage hinzugefügt. Diese verknüpfte Frage steht wirklich im Mittelpunkt dieses Problems, das nichts mit bereichsbasierten For-Schleifen zu tun hat. – TypeIA

0

Eine einfache Template-Funktion as_const kann die Besetzung nicht so hässlich machen. Ich glaube, dass das hinzugefügt wird oder kürzlich der Standardbibliothek hinzugefügt wurde.

template <typename T> T const & as_const (T const & t) { return t; } 

void f() 
{ 
    for (auto && x: as_const (y)) {} 
} 
+0

C++ 17, http://en.cppreference.com/w/cpp/utility/as_const. Es wäre sicherer, 'template void as_const (const T &&) = delete;' hinzuzufügen, um zu verhindern, dass Referenzen auf Provisorien hängen. – AlexD

+0

schön, mir war nicht bewusst, dass Sie beliebige Funktionsdeklarationen löschen können – nate

+0

'_T' ist reserviert. Benutze etwas anderes. –