9

C++ 有 ADL(Argument Dependent Lookup),正如其名称所描述的,函数的上下文(命名空间)可以从(任何)参数的上下文(命名空间)中隐含。

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对于用于对函数选项进行编码的 s,此限制尤其令人讨厌。我想知道是否有一种技术可以模拟这个特性(C++11 也可以)。假代码:

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

特别是如果 s 有解决方法enum

这段代码说明了这个问题:

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因为 then Saturday, Sunday, etc 不能直接在范围内进行(实际上using longname::days::_会给我一个编译错误)

4

1 回答 1

3

是和不是。大多数情况下没有。

坏消息是,如果枚举在当前范围之外,例如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;
}
于 2013-12-23T16:26:13.587 回答