【问题标题】:Workaround for the inverse of Argument Dependent Lookup?与参数相关的查找相反的解决方法?
【发布时间】:2014-01-03 05:21:54
【问题描述】:

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

我想不出办法。对于用于编码函数选项的enums,此限制尤其令人讨厌。我想知道是否有一种技术可以模拟这个特性(C++11 也可以)。假代码:

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

特别是如果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)
}

编辑: @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,因为Saturday、Sunday等不能直接在作用域内(事实上using longname::days::_会给我一个编译错误)

【问题讨论】:

  • 好的,提交我的问题后:我在右侧面板stackoverflow.com/questions/14163667/… 上收到了相关问题。可以说,这里的不同之处在于我不是在质疑语言,而是在寻找一种解决方法。
  • 解决方法:将枚举放在嵌套命名空间中,并在 main 中输入 using namespace longname::nested;。
  • @jrok,很酷,这更接近解决方案(我在问题中添加了您的建议)。
  • namespace Longname { enum class Days { Saturday, Monday, Odinsday }; } using Longname::Days; Longname::func( Days::Saturday, Days::Odinsday );?
  • @Yakk,谢谢我在我的编辑中添加了类似的内容,enum class 与enum 相比,更难去除噪音(但出于其他原因是必要的)。

标签: c++ c++11 enums namespaces argument-dependent-lookup


【解决方案1】:

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

坏消息是,如果枚举超出当前范围,例如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;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-03-14
    • 2021-09-14
    • 1970-01-01
    • 2018-01-08
    • 2017-05-30
    • 1970-01-01
    • 1970-01-01
    • 2015-08-26
    相关资源
    最近更新 更多