Con C++20 podemos leer el término “niebloid” con más frecuencia ahora en cppreference.
En SO podemos encontrar hoy 2020/07/16 2 artículos que lo mencionan:
- Primer comentario
- Segunda publicación, hablando de objetos de punto de personalización.
Google tampoco escupe tantos resultados. El más destacado es quizás aquí.
¿Alguien puede arrojar un poco más de luz sobre los niebloids?
El término Niebloide viene de de Eric Niebler nombre. En palabras simples, son objetos de función que deshabilitan la ADL (búsqueda dependiente de argumentos) para que las sobrecargas en std::
no se recogen cuando un algoritmo de std::ranges
se llama.
Aquí hay un tweet (de 2018) y una respuesta de eric él mismo sugiriendo el nombre. Eric escribió un artículo en 2014 explicando este concepto.
Se puede ver mejor en acción en el documento estándar en sí:
25.2.2
Las entidades definidas en el std::ranges
espacio de nombres en esta Cláusula no se encuentran mediante la búsqueda de nombres dependientes de argumentos (basic.lookup.argdep). Cuando lo encuentra un no calificado (basic.lookup.unqual) búsqueda de nombres para la expresión postfix en una llamada de función, inhiben la búsqueda de nombres dependiente de argumentos.
void foo() {
using namespace std::ranges;
std::vector<int> vec{1,2,3};
find(begin(vec), end(vec), 2); // #1
}
La expresión de llamada de función en #1
invoca std::ranges::find
no std::find
a pesar de que (a) el tipo de iterador devuelto de begin(vec)
y end(vec)
puede estar asociado con namespace std
y B) std::find
es más especializado ([temp.func.order]) que std::ranges::find
ya que el primero requiere que sus dos primeros parámetros sean del mismo tipo.
El ejemplo anterior tiene AVD apagado, por lo que la llamada va directamente a std::ranges::find
.
Vamos a crear un pequeño ejemplo para explorar esto más a fondo:
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;
}
Descripción de preferencia cp:
Las entidades similares a funciones descritas en esta página son niebloids, es decir:
- Es posible que no se especifiquen listas de argumentos de plantillas explícitas al llamar a cualquiera de ellas.
- Ninguno de ellos es visible para la búsqueda dependiente de argumentos.
- Cuando uno de ellos se encuentra mediante una búsqueda normal no calificada del nombre a la izquierda del operador de llamada de función, inhibe la búsqueda dependiente de argumentos.
Los niebloids no son visibles para la búsqueda dependiente de argumentos (ADL) porque son objetos de función, y ADL se realiza solo para funciones libres y no para objetos de función. El tercer punto es lo que sucedió en el ejemplo del estándar:
find(begin(vec), end(vec), 2); //unqualified call to find
la llamada a find()
no está calificado, por lo que cuando comienza la búsqueda, encuentra std::ranges::find
objeto de función que a su vez evita que ocurra ADL.
Buscando un poco más, encontré este que, en mi opinión, es la explicación más comprensible de niebloids y CPO (objetos de punto de personalización):
… a CPO es un objeto (no una función); es exigible; es constexpr-construible, […] es personalizable (eso es lo que significa “interactuar con tipos definidos por el programa”); y está limitado por conceptos.
[…]
Si elimina los adjetivos “personalizable, concepto restringido” de lo anterior, entonces tiene un objeto de función que desactiva ADL, pero no es necesariamente un punto de personalización.. Los algoritmos C++2a Ranges, como std::ranges::find
son así. Cualquier objeto invocable y construible constexpr se conoce coloquialmente como un “niebloide”. en honor a Eric Niebler.
De preferencia cp:
Las entidades similares a funciones descritas en esta página son niebloidseso es:
-
Es posible que no se especifiquen listas de argumentos de plantillas explícitas al llamar a cualquiera de ellas.
-
Ninguno de ellos es visible para la búsqueda dependiente de argumentos.
-
Cuando uno de ellos se encuentra mediante una búsqueda normal no calificada del nombre a la izquierda del operador de llamada de función, inhibe la búsqueda dependiente de argumentos.
En la práctica, pueden implementarse como objetos de función o con extensiones de compilador especiales.
Una definición se puede encontrar aquí: es.cppreference.com/w/cpp/algorithm/ranges/all_any_none_of en el cual
std::range::all_of
es un ejemplo de unniebloid
.– JulianH
16 de julio de 2020 a las 6:39