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>
.