2013-12-15 58 views
8

C++具有ADL(參數相關查找),正如其名稱所描述的那樣,函數的上下文(名稱空間)可以從參數(的任何一個)的上下文(名稱空間)隱含。針對參數相關查找的逆變換的解決方法?

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

我的問題是,如果反過來也有可能通過某種技術?相反,我的意思是如果上下文(名稱空間)可以從被調用函數的上下文中推導出來。某種「功能依賴查找」(FDL)。僞代碼:

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

我找不出一個辦法。這個限制對用於編碼功能選項的enum特別惱人。我想知道是否有一種技術來模擬此功能(C++ 11也可以)。僞代碼:

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

尤其是如果有解決方法enum s。

此代碼說明了問題:

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) 
} 

編輯: @jrok提出了一種基於嵌套定義命名空間的解決方法。對於enum的情況,我得到了這個代碼。這仍然有一些噪音(根本沒有「依賴」查找),但這是一個改進。

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); 
} 
我不使用 enum class因爲那時 SaturdaySunday等不能直接布拉夫範圍是

(其實using longname::days::_會給我一個編譯錯誤)

+0

OK,提交我的問題後,我得到了正確的面板上的相關問題http://stackoverflow.com/questions/14163667/why-does-c11-not-support-name-lookup-like-此?RQ = 1。可以說,這裏的區別在於我不是在質疑語言,但我正在尋找解決方法。 – alfC

+2

解決方法:將枚舉置於嵌套名稱空間中,並在'main'中聲明'using namespace longname :: nested;'。 – jrok

+0

@jrok,酷,讓一個更接近解決方案(我對你的問題添加了你的建議)。 – alfC

回答

2

是,也不是。大多數沒有。

壞消息是,如果枚舉超出當前範圍,如Tuesday等,那麼它不能傳遞給函數,即使該函數是在枚舉可見的名稱空間中聲明的。這是因爲參數查找首先發生在您編寫函數調用時,並且參數無法傳遞給gun,然後發生名稱查找。沒有什麼可以改變這一點 - 但是也有好消息。

首先,你似乎需要的行爲,地圖ns::foo(arg1, arg2) - >{using namespace ns; ns::foo(arg1, arg2);}。函數調用和模板不能改變這個,但是我可以包括宏和我的例子。

另外我給出了一個基於參數的查找示例。你可以看到使用這種機制的超範圍函數GetMonday和GetTuesday(它返回你的超範圍枚舉),只是因爲你包含了該名字空間的一個類型。 RegisterNamespace::val在編譯器嘗試查找GetMonday時將隱藏的名稱空間添加到範圍,GetMonday返回Days,允許編譯器查找foo

真的,您希望編譯器在遇到來自另一個命名空間的函數時通過添加其他名稱空間來更改範圍。然而,編譯器當時已經確定了參數的類型,並且實際上需要它們來計算函數的其他可能替代方案。

#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; 
} 
相關問題