16 Stimmen

C++ Operator-Lookup-Regeln / Koenig-Lookup

Beim Schreiben einer Testsuite musste ich eine Implementierung von operator<<(std::ostream&... für Boost Unit Test zu verwenden.

Das hat funktioniert:

namespace theseus { namespace core {
    std::ostream& operator<<(std::ostream& ss, const PixelRGB& p) {
        return (ss << "PixelRGB(" << (int)p.r << "," << (int)p.g << "," << (int)p.b << ")");
    }
}}

Das war nicht der Fall:

std::ostream& operator<<(std::ostream& ss, const theseus::core::PixelRGB& p) {
    return (ss << "PixelRGB(" << (int)p.r << "," << (int)p.g << "," << (int)p.b << ")");
}

Offenbar wurde der zweite nicht in die Kandidatenübereinstimmungen aufgenommen, als g++ versuchte, die Verwendung des Operators aufzulösen. Warum (welche Regel verursacht dies)?

Der Code, der operator<< ist tief in der Boost Unit Test Framework, aber hier ist der Test-Code:

BOOST_AUTO_TEST_SUITE(core_image)

BOOST_AUTO_TEST_CASE(test_output) {
    using namespace theseus::core;
    BOOST_TEST_MESSAGE(PixelRGB(5,5,5)); // only compiles with operator<< definition inside theseus::core
    std::cout << PixelRGB(5,5,5) << "\n"; // works with either definition
    BOOST_CHECK(true); // prevent no-assertion error
}

BOOST_AUTO_TEST_SUITE_END()

Als Referenz verwende ich g++ 4.4 (obwohl ich im Moment davon ausgehe, dass dieses Verhalten standardkonform ist).

15voto

dancl Punkte 660

Beim argumentabhängigen Lookup (der korrekte Name für Koenig-Lookup) fügt der Compiler der überladenen Funktionsmenge die Funktionen hinzu, die in den Namespaces der einzelnen Parameter deklariert sind.

In Ihrem Fall ist die erste operator<< wird im Namespace thesus::core, was der Typ des Arguments ist, mit dem Sie den Operator aufrufen. Daher ist dies operator<< wird für ADL in Betracht gezogen, weil es in einem zugehörigen Namespace deklariert ist

Im zweiten Fall ist die operator<< scheint im globalen Namespace deklariert zu sein, der kein assoziierter Namespace ist, da der erste Parameter vom Typ des Namespaces std und param 2 ist vom Typ aus dem Namensraum theseus::core .

Wahrscheinlich ist Ihr 2. operator<< ist nicht im globalen Namespace deklariert, da dies durch die Suche in übergeordneten Bereichen gefunden werden würde. vielleicht haben Sie etwas mehr wie dies? Wenn Sie mehr Code posten können, können wir eine bessere Antwort geben.


Ok, ich habe mich daran erinnert, dass ADL nicht in übergeordneten Bereichen nachsieht, wenn es einen Namen im aktuellen Bereich findet. Also das Boost-Makro BOOST_TEST_MESSAGE erweitert sich um eine operator<< und es gibt einige im Geltungsbereich Baum eine nicht lebensfähige operator<< zwischen dem Ausdruck und dem globalen Bereich. Ich habe den Code aktualisiert, um dies (hoffentlich) zu veranschaulichen.

#include <iostream>

namespace NS1
{
  class A
  {};

  // this is found by expr in NS2 because of ADL
  std::ostream & operator<<(std::ostream &, NS1::A &);
}

// this is not seen because lookup for the expression in NS2::foo stops when it finds the operator<< in NS2
std::ostream & operator<<(std::ostream &, NS1::A &);

namespace NS2
{
    class B
    {};

    // if you comment this out lookup will look in the parent scope
    std::ostream & operator<<(std::ostream &, B &);

    void foo(NS1::A &a)
    {
        std::cout << a;
    }  
}

1voto

CashCow Punkte 29849

Das Überladen von Operatoren ist wie eine Funktion, unterscheidet sich aber, und einer der Unterschiede ist die Namespace-Suche.

Wie Funktionen gehören auch Operatorüberladungen in einen Namensraum, aber ein Scoping wie bei einer Funktion wäre unpraktisch. Stellen Sie sich vor, Ihr Code müsste

std::cout thesus::core::<< p; // ouch and obviously incorrect syntax

Daher ist die << Operator muss im Namensraum eines der Parameter liegen, entweder std (für die cout ) oder den Namespace des p In diesem Fall thesus::core .

Dies ist das Koenig-Lookup-Prinzip. Sie müssen die Operatorüberladung im richtigen Namespace definieren.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X