c++ c++11 templates

c++ - ¿Qué significa vacío, o cómo afecta a T en este caso?



c++11 templates (3)

Así que estaba trabajando con un amigo mío en C ++, y nos encontramos con esto en la documentación.

//(until C++14) template<class T> struct less;

//(since C++14) template<class T = void> struct less;

Ahora sé cómo funciona con la class T = int y lo mismo para double y float y otros tipos de clases. Pero la parte con la que estoy muy confundido es, ¿cómo actúa el vacío en este caso? ¿Y cuáles son las limitaciones al usar void?

Lo pregunto porque la documentación de C ++ es muy útil y no puedo encontrar ningún otro lugar que lo explique.


Dado su fragmento de código, voy a suponer que está refiriendo el objeto de función de la biblioteca estándar, es decir, en.cppreference.com/w/cpp/utility/functional/less .

En general, la template<class T = void> declaración template<class T = void> funciona exactamente como para otros tipos (como int , por ejemplo). En resumen, cuando un objeto de esa clase se instancia sin especificar el argumento de plantilla de tipo, entonces se deducirá void .

std::less<int> li; // std::less<T = int>; std::less<void> lv; // std::less<T = void>; std::less<> lv2; // std::less<T = void>; exactly as one row above.

En este caso particular, std::less proporciona una especialización de plantilla cuando T = void .

El objeto std::less<void> es una práctica especialización que permite deducir los tipos para comparar "automáticamente" con el operator() . Además, es necesario cuando desea comparar dos tipos diferentes que no son implícitamente convertibles.

Ejemplo práctico

Supongamos que tiene dos objetos que puede comparar.

/*Let us assume you have two objects you can compare*/ struct Foo; struct Bar; struct Foo { bool operator<(const Bar&) const; }; struct Bar { bool operator<(const Foo&) const; };

Foo y Bar se pueden comparar entre sí, pero son de diferentes tipos.

¿Qué tipo de plantilla especificará para el functor std::less en este caso?

void WrongCode() { std::less<Foo> l; l(Foo{}, Bar{}); // error }

Si usamos std::less<Foo> entonces el functor solo aceptará objetos de tipo Foo . (Por supuesto, lo mismo es para std::less<Bar> ).

Por lo tanto, el estándar proporciona esta práctica especialización para cubrir este caso.

void GoodCode() { std::less<> l; l(Foo{}, Bar{}); // this compile }

GoodCode se compilará porque los tipos de operator() de std::less<void> se deducen automáticamente (e incluso pueden ser diferentes).


En general, solo significa que va a especializar una clase para que el tipo vacío procese un caso especial.

Aquí hay un programa demostrativo.

#include <iostream> template <class T = void> struct A { void operator ()( const T & t ) const { std::cout << "primary template/n"; std::cout << 2 * t << ''/n''; } }; template <> struct A<> { template <typename U> void operator ()( const U &u ) const { std::cout << "specialization for void/n"; std::cout << 10 * u << ''/n''; } }; int main() { A<int>()( 1 ); A<>()( 1 ); }

Su salida es

primary template 2 specialization for void 10


void es un tipo.

Existen algunas restricciones sobre cómo se puede usar el tipo void , pero, sin embargo, void es un tipo válido en el sistema de tipos. Por lo tanto, se permite tener void como argumento para un parámetro de plantilla, incluido como argumento predeterminado.

Entonces, si escribe std::less<> entonces significa std::less<void> .

La pregunta de qué significa std::less<void> es diferente: normalmente, std::less<T> compara T valores de T , pero no hay valores de tipo void . En cambio, std::less<void> es un caso especial: puede pasarle dos valores de cualquier tipo (posiblemente diferente), siempre que puedan compararse. Consulte std::less<void> .