参数依赖查找的反转的解决方法?

alf*_*lfC 9 c++ enums namespaces argument-dependent-lookup c++11

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

fun(a); // if the type of a is in namespace ns deduce ns::f if available
Run Code Online (Sandbox Code Playgroud)

我的问题是,通过某种技术是否也可以反过来?反过来我的意思是如果可以从被调用函数的上下文推导出上下文(命名空间).某种"功能依赖查找"(FDL).假代码:

ns::fun(a); // deduce ns::a if available
Run Code Online (Sandbox Code Playgroud)

我无法弄清楚这样做的方法.对于enum用于编码功能选项的s来说,这种限制尤其令人讨厌.我想知道是否有一种模拟此功能的技术(C++ 11也可以).假代码:

ns::fun(Saturday, Tuesday); // Saturday/Tuesday are enum values in namespace ns;
Run Code Online (Sandbox Code Playgroud)

特别是如果有enums 的解决方法.

此代码说明了此问题:

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)
}
Run Code Online (Sandbox Code Playgroud)

编辑: @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);
}
Run Code Online (Sandbox Code Playgroud)

我没有使用enum class因为那时Saturday,Sunday等等不能直接在范围内(事实上using longname::days::_会给我一个编译错误)

use*_*280 3

是和不是。大多没有。

坏消息是,如果枚举超出当前范围,例如Tuesday等,则它无法传递给函数,即使该函数是在枚举可见的命名空间中声明的。这是因为当您编写函数调用时,首先会进行参数查找,并且无法将参数传递给gun然后进行名称查找。没有什么可以改变这一点——但是也有好消息。

首先,您似乎需要映射ns::foo(arg1, arg2)->的行为{using namespace ns; ns::foo(arg1, arg2);}。函数调用和模板不能改变这一点,但宏可以改变这一点,我包括了示例。

我还给出了参数相关查找的基本示例。您可以看到,可以使用此机制找到超出范围的函数 GetMonday 和 GetTuesday(返回超出范围的枚举),因为您包含了该命名空间中的一种类型。RegisterNamespace::val当编译器尝试查找 GetMonday 时,将隐藏命名空间添加到作用域,并且 GetMonday 返回 a 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;
}
Run Code Online (Sandbox Code Playgroud)