2013-12-15 18 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; 
} 
相关问题