¿Qué es un niebloide?

5 minutos de lectura

avatar de usuario
Armin Montigny

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?

avatar de usuario
Waqar

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​::​findno std​::​finda 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::findson así. Cualquier objeto invocable y construible constexpr se conoce coloquialmente como un “niebloide”. en honor a Eric Niebler.

  • Los niebloides son no garantizados para ser objetos. Se especifican como plantillas de funciones mágicas con suficiente redacción comadreja para permitir que se implementen como objetos, pero no más.

    – CT

    17 de julio de 2020 a las 4:53

  • Cuando leo publicaciones como esta, me doy cuenta de lo mucho que no sé.

    – Galaxia

    21 de julio de 2020 a las 20:37

  • Disculpen mi ignorancia. Es (f)(x) no impide que suceda ADL?

    – Chef Gladiador

    19 de marzo de 2021 a las 10:41

  • “Función inmune ADL” de esa encuesta parece un nombre autodescriptivo mucho mejor. ¿Por qué no se usa eso en su lugar?

    – gracias

    16 abr 2021 a las 15:12

  • Sugerí “niebloid” con la lengua firmemente en la mejilla. Para mi disgusto, se quedó. Me sirve bien.

    –Eric Niebler

    6 oct 2021 a las 0:40

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.

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad