我试图为我的模板类operator|
编写boo
,一切正常,直到模板类是一个提升范围类型 - 就像示例中的{{1} } - adl优先于本地boost::range::filter_range
。
有人可以解释为什么adl更倾向于通过本地命名空间来提升这个详细命名空间的重载吗?
boost::range_detail::operator|(SinglePassRange& r, const replace_holder<T>)
}
clang错误(msvc报告几乎相同):
#include <vector>
#include <boost/range/adaptors.hpp>
namespace local
{
template<typename T>
struct boo {};
// this overload is not prefered when T is a boost::range::xxx_range
template<typename T, typename U>
auto operator|(boo<T>, U)
{
return false;
}
void finds_local_operator_overload()
{
std::vector<int> xs;
// works like expected and calls local::operator|
auto f = boo<decltype(xs)>{} | xs;
}
void prefers_boost_range_detail_replaced_operator_overload_instead_of_local_operator()
{
std::vector<int> xs;
// compiler error because it tries to call 'boost::range_detail::operator|'
auto filtered = xs | boost::adaptors::filtered([](auto &&x){ return x % 2; });
auto f = boo<decltype(filtered)>{} | xs;
}
答案 0 :(得分:2)
根据ADL的规则,
集合中为boo<decltype(filtered)>{} | xs
的重载添加的名称空间和类是local
(对于boo
),boost::range_detail
(对于decltype(filtered)
)和std
( std::vector<int>
xs
}。
我们有特殊性:
(正如您所期望的那样,您在local
template<typename T, typename U> auto operator|(boo<T>, U);
和)
boost::range_detail
中有问题的一个:
template <class SinglePassRange>
replaced_range<const SinglePassRange>
operator|(
const SinglePassRange&,
const replace_holder<typename range_value<SinglePassRange>::type>&);
所以我们有非推断的range_value<boo<decltype(filtered)>>::type
引发了一个很难的错误。 (遗憾的是,该方法不能从过载集中删除SFINAE友好。)
错误发生在overload_resolution之前。