ProgrammatieC++ ontwikkelaar

Wat is ADL (Argument Dependent Lookup, argumentafhankelijke zoekopdracht) in C++? Hoe werkt het en wanneer kan het leiden tot onverwachte resultaten?

Slaag voor sollicitatiegesprekken met de Hintsage AI-assistent

Antwoord.

Achtergrond van de vraag: ADL (Argument Dependent Lookup), ook bekend als Koenig lookup, verscheen voor het eerst in C++ ter ondersteuning van operatoroverloading (vooral operator<< en operator>> voor gebruikersgedefinieerde types). Het doel is om functies correct te vinden bij het mengen van naamruimten en gebruikersgedefinieerde types.

Probleem: Het standaardmechanisme voor het zoeken naar functies kan een functie "missen" als deze is gedeclareerd in een andere namespace dan het punt van aanroep. ADL lost dit probleem op: de compiler houdt rekening met de naamruimte van de argumenttypes van de functie om namen op te lossen. Ditzelfde mechanisme kan soms leiden tot onverwachte keuze van overbelasting of ambiguïteiten.

Oplossing: Wanneer een functie wordt aangeroepen waarvan de argumenten objecten zijn uit gebruikerspecifieke naamruimten, zoekt de compiler naar geschikte overloaded functies, niet alleen in de huidige scope, maar in alle naamruimten die verband houden met de types van de argumenten.

Voorbeeldcode:

namespace lib { struct Widget {}; void do_something(const Widget&) { std::cout << "Widget" << std::endl; } } using lib::Widget; void call(const Widget& w) { do_something(w); // do_something wordt gevonden via ADL }

Belangrijkste kenmerken:

  • Maakt het mogelijk om functies buiten de globale namespace te overladen
  • Maakt het mogelijk om universele code te schrijven (bijvoorbeeld, operator<< voor std::ostream en gebruikersklassen)
  • Kan leiden tot onverwachte keuze van overbelasting als er meerdere geschikte functies zijn in verschillende naamruimten

Misleidende vragen.

Als je een functie met dezelfde naam in twee naamruimten declareert en een object van de tweede doorgeeft, welke wordt dan aangeroepen?

De functie uit de naamruimte van het argument, als deze geschikt is voor de argumenten, zal worden gekozen door ADL:

namespace A { struct S {}; void f(const S&) { std::cout << "A!"; } } namespace B { struct S {}; void f(const S&) { std::cout << "B!"; } } A::S a; B::S b; f(a); // roept A::f aan via ADL f(b); // roept B::f aan via ADL

Werkt ADL met sjabloonfuncties?

Ja, als de sjabloonfunctie is gedefinieerd in de namespace die overeenkomt met het type van het argument, zal ADL deze vinden bij het aanroepen met dat type.

Zal ADL werken voor functiepointers?

Nee, ADL wordt niet toegepast bij het verkrijgen van een pointer naar een functie (bijvoorbeeld, bij het nemen van het adres daarvan). Alleen bij de directe aanroep van de functie.

Typische fouten en antipatterns

  • Plotselinge "zichtbaarheid" van een andere functie dan verwacht (wanneer namen gelijk zijn)
  • Willekeurige ambiguïteit door het overlappen van namen
  • Mogelijkheid om onduidelijke overbelastingen door te geven via de naamruimte van de argumenten

Voorbeeld uit het leven

Negatieve case

Een project heeft verschillende externe bibliotheken aangesloten, waarbij in elke namespace zijn eigen print() was. In de hoofdcode werd print() gebruikt met objecten van verschillende klassen. Door ADL begon de compiler de functie uit de verkeerde naamruimte te "kiezen".

Voordelen:

  • Universaliteit van code schrijven

Nadelen:

  • De code wordt onduidelijk, er verschijnen bugs door naamconflicten

Positieve case

Gebruik van qualified call (expliciete vermelding van namespace):

lib::do_something(w); // Expliciet!

Voordelen:

  • Volledige eenduidigheid van de aanroep

Nadelen:

  • Meer omslachtige notatie