2017-07-12 1 views
2

Beim Versuch, den folgenden Code zu kompilieren (ab ursprünglichem vereinfacht):g ++ std :: Satz kann nicht Operator finden <für die Klasse definiert

#include <cstdlib> 
#include <iostream> 
#include <set> 

namespace OrbitSets { 
    class rational; 
} 

bool operator<(OrbitSets::rational a, OrbitSets::rational b); 

namespace OrbitSets { 

    // Class definition 
    class rational { 
    private: 
     long long numerator; 
     long long denominator; 
    public: 
     rational() { 
      numerator = 0; 
      denominator = 1; 
     } 
     rational(int a) { 
      numerator = a; 
      denominator = 1; 
     } 

     friend bool ::operator<(rational a, rational b); 
    }; 
} 

// Ordering operations 
inline bool operator<(OrbitSets::rational a, OrbitSets::rational b) { 
    return a.numerator * b.denominator < b.numerator * a.denominator; 
} 

int main() { 
    const OrbitSets::rational a = 5; 
    const OrbitSets::rational b = 3; 

    std::set<OrbitSets::rational> c; 
    c.insert(a); 

    if (a < b) return 1; 

    return 0; 
} 

gcc beschwert sich über die c.insert Linie, die es nicht Operator finden < für die OrbitSets :: rationale Klasse, die folgende Fehlermeldung geben:

/usr/include/c++/5/bits/stl_function.h:387:20: error: no match for ‘operator<’ (operand types are ‘const OrbitSets::rational’ and ‘const OrbitSets::rational’) 
     { return __x < __y; } 

wenn jedoch die c.insert (a) Linie zu kommentieren weg, kompiliert der Code korrekt, auch wenn zwei Zeilen später ein ähnlicher Vergleich gemacht wird, mit die gleiche Art von Argumenten.

Ich benutze g ++, um dies zu kompilieren, warum ist es nicht möglich, den oben genannten Operator für die Verwendung in der weniger Vorlageklasse zu finden, ist aber in der Lage, es für die Verwendung 2 Zeilen später zu finden?

+3

Setzen Sie den Operator in den gleichen Namensraum wie 'rational'. –

Antwort

3

Wenn set::insert versucht, den Ausdruck __x < __y auszuwerten, um Ihre Objekte zu vergleichen, führt der Compiler eine Argument-Dependent Lookup.

Der erste Schritt ist Unqualified Name Lookup. Da der Ausdruck innerhalb von namespace std verwendet wird, findet diese Suche mehrere Funktionen std::operator< (wie Sie in der langen Compilerfehlerausgabe sehen können) und stoppt dort.

Dann ermittelt der Compiler, was die "zugeordneten Namespaces und Klassen" für den Funktionsaufruf sind. Da beide Argumente denselben Klassentyp haben, ist die einzige zugeordnete Klasse OrbitSets::rational und der einzige zugehörige Namespace ist OrbitSets.

Da sich Ihr operator< im globalen Namespace befindet, wird er nicht vom zugeordneten Namespace-Lookup gefunden.

Was ich nicht verstehe, ist doch, warum Regel [basic.argdep.lookup] /4.2 gilt nicht:

  • Any namespace-scope friend functions or friend function templates declared in associated classes are visible within their respective namespaces even if they are not visible during an ordinary lookup.

mir scheint, Sie haben zu tun einen Namespace-scope Freund-Funktion, die deklariert in einer zugeordneten Klasse, obwohl es nicht die erste Deklaration ist. Aber beide g ++ und Klirren ++ den gleichen Fehler geben, und zumindest einer von ihnen ist in der Regel recht ....

Ihre (a < b) Ausdruck ist nicht in einem Umfang andere operator< enthalten, so dass der Satz von ::operator< Überlastungen im globalen Namespace , einschließlich der, die du meintest, wird in diesem Fall gefunden.

In jedem Fall können Sie dies beheben, indem Sie Ihre operator< innerhalb namespace OrbitSets verschieben.

+0

Da der 'operator <' im globalen Bereich definiert ist, handelt es sich nicht um eine * namespace-scope-Friend-Funktion *? – NathanOliver

+1

[basic.scope.namespace]/3 "Der äußerste deklarative Bereich einer Übersetzungseinheit ist auch ein Namespace namens _global namespace_. Ein im globalen Namespace deklarierter Name hat _global namespace scope_ (auch _global scope_ genannt)." – aschepler

Verwandte Themen