最近,我遇到了 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 和模板参数推导如何逐步找到最佳匹配?
是否存在同一个“主体”会优先选择成员(member)功能而不是自由功能的情况? (这就是产品构建中发生的情况)
提前致谢。
最佳答案
这是详细发生的事情,也是每个编译器应该做的:通过限定查找找到候选模板函数
template <typename T>
test::Ops::operator<<(const T&)
而第二个候选是通过 ADL 使用模板参数推导(cfr. temp.deduct.conv)生成的
template <template <typename> class E, typename T>
test::operator<<(test::Ops&, const E<T>&)
此后,重载决议启动(参见 13.3.3),并且非成员 (F1) 优先于成员 (F2),因为
- F1 and F2 are function template specializations, and the function template for F1 is more specialized than the template for F2 according to the partial ordering rules described in 14.5.6.2.
因此选择作为要调用的函数。
回答你的问题:这取决于重载解析规则。作为成员函数或在内部作用域中不会影响结果,例如
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
被分配了一个非整数类型。
关于c++ - ADL 应该如何发挥作用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26000553/