ADL应该如何工作

How should ADL work for this?

本文关键字:工作 何工作 ADL      更新时间:2023-10-16


最近,我遇到了clang++5.0.0编译器的一个问题,通过ADL,它没有在Mac上获得正确的函数(但g++在Linux上做得正确)。我想知道这是编译器问题还是一般的类设计不好
下面是一个示例代码(纯粹用于说明目的):

namespace test {
    class Ops {
      public:
        Ops():val_(0){}
        template<typename T>
        Ops& operator<< (const T& val) {
            std::cout << "Called member function" << std::endl;
            this->val_ = val;
            return *this;
        }
      private:
        int val_;
    };
    template<typename T>
    struct Any {
        T val_;
    };
    template <template<typename> class E,  typename T>
    Ops& operator<< (Ops& op, const E<T>& val) {
        std::cout << "Global function" << std::endl;
        return op;
    }
}
int main() {
    test::Ops op;
    int k = 9;
    test::Any<int> a;
    op << a;
    return 0;
}

我想知道ADL和模板论点推导将如何以循序渐进的方式找到最佳匹配
对于同一个"主体",是否有任何情况下会首选成员功能来代替自由功能?(这就是产品构建中发生的情况)

提前谢谢。

这是详细发生的事情,也是每个编译器应该做的事情:通过限定查找找到候选模板函数

template <typename T>
test::Ops::operator<<(const T&)

而第二候选是通过ADL使用模板参数推导(cfr.temp.dexeract.conv)生成的

template <template <typename> class E, typename T>
test::operator<<(test::Ops&, const E<T>&)

之后,过载解决方案开始生效(参见13.3.3),由于,非成员(F1)优先于成员(F2)

  • F1和F2是函数模板专业化,F1的函数模板更专业而不是根据14.5.6.2中描述的偏序规则的F2的模板

从而被选择为要调用的函数。

回答您的问题:这取决于过载解决规则。作为成员函数或在内部范围内不会影响结果和之类的东西

namespace test {
    class Ops {
      public:
        Ops():val_(0){}
        template<typename T>
        Ops& operator<< (const T& val) {
            std::cout << "Called member function" << std::endl;
            this->val_ = val;
            return *this;
        }
      private:
        int val_;
    };
    template<typename T>
    struct Any {
        T val_;
    };
    template <typename E>
    Ops& operator<< (Ops& op, const E& val) {
        std::cout << "Global function" << std::endl;
        return op;
    }
}

只会触发过载解析错误"use of overloaded operator '<<' is ambiguous"。

另外:即使选择了成员函数,它也是错误的:this->val被分配了一个非整数类型。

这两个候选函数在重载集中:

// member function template, found by qualified lookup
template <typename T>
test::Ops::operator<<(const T&)
// non-member function template, found by ADL
template <template <typename> class E, typename T>
test::operator<<(test::Ops&, const E<T>&)

在运算符查找中,没有对成员和非成员进行优先选择。在模板参数替换之后,两个函数模板专门化与所提供的参数类型完全匹配(具有限定转换)。但取E<T>的函数比取T的函数更专业,因此选择非成员函数是出于这个原因。

Apple clang 5.0.0基于LLVM clang 3.3svn。我找不到任何选择成员函数的LLVM claang版本。这可能是苹果代码中的一个错误,但IMHO,这更有可能是你实际编译的代码或你的环境中的一些细微差异。您是否尝试过使用可疑的编译器编译示例代码?