2013-12-15 3 views
8

C++ hat ADL (Argument Dependent Lookup), mit dem, wie sein Name beschreibt, der Kontext (Namespace) einer Funktion aus dem Kontext (Namespace) von (jedem der) Argumente impliziert werden kann.Workaround für die Umkehrung der Argument abhängigen Suche?

fun(a); // if the type of a is in namespace ns deduce ns::f if available 

Meine Frage ist, wenn die umgekehrte durch irgendeine Technik auch möglich ist? Umgekehrt meine ich, wenn der Kontext (Namespace) aus dem Kontext der aufgerufenen Funktion abgeleitet werden kann. Eine Art von "Function Dependent Lookup" (FDL). Gefälschter Code:

ns::fun(a); // deduce ns::a if available 

Ich kann einen Weg nicht herausfinden. Diese Einschränkung ist besonders ärgerlich für enum s, die zum Codieren von Funktionen verwendet werden. Ich würde gerne wissen, ob es eine Technik gibt, um diese Funktion zu simulieren (C++ 11 wäre auch in Ordnung). Gefälschte Code:

ns::fun(Saturday, Tuesday); // Saturday/Tuesday are enum values in namespace ns; 

Vor allem, wenn es eine Abhilfe für enum s.

Dieser Code zeigt das Problem:

namespace longname{ 
    class A{}; 
    void fun(A const& a){} 
    A global_a; 

    enum Days { Saturday,Sunday,Tuesday,Wednesday,Thursday,Friday}; 
    void gun(Days d1, Days d2){}  
} 

int main(){ 
    longname::A a; 
    fun(a); // cool, longname::fun(a) not necessary, fun is deduced from context 

    longname::fun(global_a); // error, not cool, global_a context not deduced, 
    // must use then longname::fun(longname::global_a) 
    longname::gun(Saturday, Tuesday); // error, particularly not cool, the Saturday is not deduced from context 
    // must use then longname::gun(longname::Saturday, longname::Tuesday) 
    // or at best gun(longname::Saturday, longname::Tuesday) 
} 

EDIT: @jrok eine Abhilfe vorgeschlagen, basierend auf verschachtelten Namensraum zu definieren. Für den enum Fall erhalte ich diesen Code. Das hat immer noch etwas Lärm (es gibt überhaupt keine "abhängige" Nachschau), aber es ist eine Verbesserung.

namespace longname{ 
    namespace days{ 
     enum _ { Saturday,Sunday,Tuesday,Wednesday,Thursday,Friday}; 
    } 
    void gun(days::_ d1, days::_ d2){} 
} 

int main(){ 
    using namespace longname::days; // some noise still here 
    longname::gun(Saturday, Tuesday); 
} 

ich nicht enum class verwenden, weil dann Saturday, Sunday, etc nicht brough direkt im Umfang sein kann (in der Tat using longname::days::_ würde ich einen Compiler-Fehler)

+0

ok, nach meiner Frage einreichen: Ich habe eine ähnliche Frage auf der rechten Seite http://stackoverflow.com/questions/14163667/why-does-c11-not-support-name-lookup-like- das? rq = 1. Wahrscheinlich ist der Unterschied hier, dass ich die Sprache nicht in Frage stelle, aber ich suche nach einer Workaround-Technik. – alfC

+2

Workaround: Setzen Sie die Enumeration in einen verschachtelten Namespace und sagen Sie '' namespace longname :: nested; 'in' main'. – jrok

+0

@jrok, cool, das bringt dich näher an eine Lösung heran (ich habe deinen Vorschlag der Frage hinzugefügt). – alfC

Antwort

2

Ja und nein. Meist nicht.

Die schlechte Nachricht ist, wenn eine Enumeration außerhalb des aktuellen Bereichs ist, wie Tuesday usw. dann kann es nicht an eine Funktion übergeben werden, auch wenn diese Funktion in einem Namespace deklariert wurde, wo die Enumeration sichtbar war. Dies liegt daran, dass die Argumentsuche zuerst erfolgt, wenn Sie einen Funktionsaufruf schreiben und die Argumente nicht an gun übergeben werden können und dann eine Namenssuche durchgeführt wird. Nichts kann das ändern - aber es gibt auch gute Nachrichten.

Zunächst scheinen Sie Verhalten zu benötigen, das ns::foo(arg1, arg2) ->{using namespace ns; ns::foo(arg1, arg2);} abbildet. Funktionsaufrufe und Templates können dies nicht ändern sondern Makros können und ich und Beispiel enthalten.

Auch ich gab ein grundlegendes Beispiel für Argument abhängigen Lookup. Sie können sehen, dass die Out-of-Scope-Funktionen GetMonday und GetTuesday (die Ihre Out-of-Scope-Enum ausgeben) mithilfe dieses Mechanismus gefunden werden können, weil Sie nur einen Typ aus diesem Namespace aufgenommen haben. RegisterNamespace::val fügt dem Scope den versteckten Namespace hinzu, wenn der Compiler versucht, GetMonday zu finden, und GetMonday gibt Days zurück, wodurch der Compiler foo finden kann.

Wirklich möchten Sie den Compiler den Bereich ändern, indem Sie zusätzliche Namespaces hinzufügen, wenn es eine Funktion aus einem anderen Namespace trifft. Allerdings hat der Compiler die Typen der Argumente bereits bestimmt und benötigt sie, um andere mögliche Alternativen zu der Funktion zu ermitteln.

#include <iostream> 

namespace hidden { 

enum RegisterNamespace { val }; 

enum Days { 
    Monday, 
    Tuesday 
}; 

void foo(Days a , Days b){std::cout << "Called foo\n";} 

Days GetMonday(RegisterNamespace a = val){return Days::Monday;} 
Days GetTuesday(RegisterNamespace b = val){return Days::Tuesday;} 

} 

using namespace std; 

#define UseNamespace(ns, x) do {using namespace ns; x;} while (0) 

int main() 
{ 
    //with a macro 
    UseNamespace(hidden,hidden::foo(Monday, Tuesday)); 

    { 
    //foo is found by argument dependent lookup 
    using hidden::Days; 
    foo(Days::Monday,Days::Tuesday); 
    } 

    { 
    using r = hidden::RegisterNamespace; 
    //foo and GetMonday/GetTuesday are all found by argument dependent lookup 
    foo(GetMonday(r::val),GetTuesday(r::val)); 
    } 

    return 0; 
} 
Verwandte Themen