发布于 2020-07-16 06:45:09
术语niebloid来自于Eric的名称。简单地说,它们是函数对象,它们禁止ADL (依赖于参数的查找)的发生,以便在调用std::ranges的算法时不会捕获std::ranges中的重载。
这是一条(2018年的)推文,他自己给出了这个名字的答案。埃里克在2014年写了一个文章来解释这个概念。
最好在标准文件本身中看到它的作用。
25.2.2 在本条款中的
std::ranges命名空间中定义的实体不能通过依赖于参数的名称查找(basic.lookup.argdep)找到。当在函数调用中通过不限定(basic.lookup.unqual)名称查找查找后缀表达式时,它们会抑制依赖于参数的名称查找。 void (){使用命名空间std::range;std::vec{1,2,3};find(std(Vec),end(vec),2);// #1 }#1中的函数调用表达式调用的是std::ranges::find,而不是std::find,尽管(a)从begin(vec)和end(vec)返回的迭代器类型可能与namespace std相关联,(b)std::find比std::ranges::find更专业化(temp.func.order),因为前者要求前两个参数具有相同的类型。
上面的示例关闭了ADL,因此调用直接转到std::ranges::find。
让我们创建一个小示例来进一步探讨这个问题:
namespace mystd
{
class B{};
class A{};
template<typename T>
void swap(T &a, T &b)
{
std::cout << "mystd::swap\n";
}
}
namespace sx
{
namespace impl {
//our functor, the niebloid
struct __swap {
template<typename R, typename = std::enable_if_t< std::is_same<R, mystd::A>::value > >
void operator()(R &a, R &b) const
{
std::cout << "in sx::swap()\n";
// swap(a, b);
}
};
}
inline constexpr impl::__swap swap{};
}
int main()
{
mystd::B a, b;
swap(a, b); // calls mystd::swap()
using namespace sx;
mystd::A c, d;
swap(c, d); //No ADL!, calls sx::swap!
return 0;
}来自优先选择的描述
本页中描述的类函数实体是niebloid,即:
Niebloid对于参数相关查找( ADL )是不可见的,因为它们是函数对象,而ADL只针对空闲函数而不是函数对象。第三点是标准示例中发生的情况:
find(begin(vec), end(vec), 2); //unqualified call to find对find()的调用是不限定的,所以当查找开始时,它会找到std::ranges::find函数对象,从而阻止ADL的发生。
搜索更多内容后,我发现了这,在我看来,这是对niebloid和CPOs (定制点对象)最容易理解的解释:
..。CPO是一个对象(不是函数);它是可调用的;它是可构造的,.它是可定制的(这就是“与程序定义的类型交互”的意思);而且它是受概念约束的。 ..。 如果从上面删除形容词“可定制的、受概念约束的”,那么就有一个关闭ADL的函数对象--但不一定是自定义点。C++2a范围算法,如
std::ranges::find,是这样的。任何可调用的、可构造的对象都被俗称为“niebloid”,以纪念Eric。
发布于 2020-08-12 20:42:58
来自优先选择
本页面中描述的类函数实体是niebloids,即:
在实践中,它们可以实现为函数对象,或使用特殊的编译器扩展。
https://stackoverflow.com/questions/62928396
复制相似问题