7

情况是某些成员函数bar::Bar::frobnicate想利用 ADL 从某个未知名称空间中找到一个函数,该函数在一个具有相同名称的函数中。但是,它只能找到自己的名称。

测试用例

请注意,实际上,Bar是一个Foo不可知的模板;这只是可重现的最小测试用例)

namespace foo {
    struct Foo {};
    void frobnicate(Foo const &) {}
}

namespace bar {
    struct Bar {
        void frobnicate() {
            foo::Foo foo;
            frobnicate(foo); // <-- error
        }
    };
}

int main () {
    bar::Bar x;
    x.frobnicate();
    frobnicate(foo::Foo());
}

结果是:

test.cc: In member function ‘void bar::Bar::frobnicate()’:
test.cc:10:31: error: no matching function for call to ‘bar::Bar::frobnicate(foo::Foo&)’
test.cc:10:31: note: candidate is:
test.cc:8:18: note: void bar::Bar::frobnicate()
test.cc:8:18: note:   candidate expects 0 arguments, 1 provided

标准

我知道这是正确的编译器行为:

3.4.1 非限定名称查找[basic.lookup.unqual]

(...) 一旦找到名称 (...) 的声明,名称查找就会结束

并且只有不合格的查找失败后,依赖于参数的查找才起作用:

3.4.2 依赖于参数的名称查找[basic.lookup.argdep]

当函数调用 (5.2.2) 中的后缀表达式是非限定 ID 时,可能会搜索在通常的非限定查找 (3.4.1) 期间未考虑的其他命名空间

解决方法

我目前的解决方法是引入一个不定义冲突名称本身的特殊特征类:

    struct BarTraits {
        void frobnicate_(foo::Foo const &b) {
            frobnicate(b);
        }
    };

或者这个更轻的版本:

    void frobnicate_(foo::Foo const &c) { frobnicate(c); }

问题

有没有比引入此类特征类更好的选择?

在这里明确限定调用foo::frobnicate(foo)不是一个选项,因为(如前所述)Bar该类实际上是一个模板,Foo并且不应仅适用于foo命名空间中的类型。

4

3 回答 3

2

正如您自己发现的那样,将成员函数添加到(或在模板情况下)frobnicate的类接口中,将阻止 ADL 找到.BarBar<T>foo::frobnicate

向类(或类模板)添加功能的最简单(在这种情况下也是惯用的)方法是将非成员函数 (或函数模板)添加到命名空间frobnicateBarBar<T>frobnicate(Bar)frobnicate(Bar<T>)bar

namespace foo {
    struct Foo {};
    void frobnicate(Foo const &)  {}
}

namespace bar {
    template<class T>
    struct Bar {    
       T t;    
    }; 

    template<class T>
    void frobnicate(Bar<T> const& b)
    {
        frobnicate(b.t);    
    }
}

int main () {
    bar::Bar<foo::Foo> x;
    frobnicate(x);
    frobnicate(foo::Foo());
}

如果您坚持使用成员函数,则必须将其重命名为do_frobnicate(). 我不会使用类型特征技巧来获得与间接方法相同的行为,并使类接口更难理解(记住 Stroustrup 的座右铭:“直接在代码中表达你的想法”)。

于 2013-07-24T06:32:28.617 回答
1

你可以使用这个技巧

namespace dummy { void your_func(may be some parameteres); }
struct bar { 
   void member() {
      using dummy::your_func; // now your call will find that and ADL will kick in
于 2013-09-27T09:53:55.410 回答
0

我只是用代理功能来做

namespace utils 
{
int lookup_adl(int arg) 
{
  return lookup(arg);// ADL search
}
struct Foo 
{
  int lookup(int arg) { return ::utils::lookup_adl(arg);}
};
}
于 2020-04-28T08:51:49.830 回答