c++ - ADL 在同名成员函数的情况下

标签 c++ interface argument-dependent-lookup non-member-functions

情况是某些成员函数 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 Unqualified name lookup [basic.lookup.unqual]

(...) name lookup ends as soon as a declaration is found for the name (...)

只有非限定查找失败后,参数依赖查找才会起作用:

3.4.2 Argument-dependent name lookup [basic.lookup.argdep]

When the postfix-expression in a function call (5.2.2) is an unqualified-id, other namespaces not considered during the usual unqualified lookup (3.4.1) may be searched

解决方法

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

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

或者这个更轻的版本:

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

问题

是否有比引入此类特征类更好的替代方案?

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

最佳答案

正如您自己发现的那样,添加一个成员函数 frobnicateBar 的类接口(interface)(或模板案例中的 Bar<T>),将阻止 ADL 找到 foo::frobnicate .

最简单的 - and in this case idiomatic - 添加方式frobnicate类的功能 Bar (或类模板 Bar<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() 的名称。 .我不会使用类型特征技巧来获得相同的行为,因为它是一种间接方法,并且会使类接口(interface)更难理解(记住 Stroustrup 的座右铭:“直接在代码中表达你的想法”)。

关于c++ - ADL 在同名成员函数的情况下,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17826307/

相关文章:

c++ - 无法显式访问命名空间范围友元

c++ - 在 C++ 中使用指针 vector 时会泄漏内存吗?

c++ - 如何在 C++ 中声明自定义类型的成员对象并随后进行初始化?

c++ - 为什么分配器接口(interface)封装嵌套类的 "list"实现也受益于封装节点?

c# - 隐式内部接口(interface)实现

java - 如何避免 'Interface Abstract class error' ?

c++ - 覆盖 ADL 选择的重载

c++ - "source code"和 "translation unit"之间有什么特别的区别吗?

java - 将新的 JavaDoc 附加到来自 super 方法的现有 JavaDoc

c++ - 参数相关名称查找 : add extra namespace to look into