programas - sintaxis de c++ definicion
cómo saber si un tipo de plantilla de C++ es una cadena de estilo C (5)
Desea verificar si el tipo es el mismo que un char * , pero está negando el resultado de std::is_same , que claramente no va a producir el resultado correcto. Así que vamos a eliminar eso.
template<class T>
struct is_c_str
: std::integral_constant<
bool,
std::is_same<char *, typename std::remove_reference<typename std::remove_cv<T>::type>::type>::value
> {};
Sin embargo, esto ahora dará como resultado la salida 0, 0, 0 . El problema ahora es que remove_cv elimina los calificadores cv de nivel superior, pero la const en char const * no es de nivel superior.
Si desea hacer coincidir tanto char * como char const * la solución más sencilla es:
template<class T>
struct is_c_str
: std::integral_constant<
bool,
std::is_same<char *, typename std::remove_reference<typename std::remove_cv<T>::type>::type>::value ||
std::is_same<char const *, typename std::remove_reference<typename std::remove_cv<T>::type>::type>::value
> {};
La versión anterior aún no coincidirá con char[] . Si también desea hacer coincidir esos, y reducir la verbosidad de combinar std::remove_reference y std::remove_cv , use std::decay lugar.
template<class T>
struct is_c_str
: std::integral_constant<
bool,
std::is_same<char const *, typename std::decay<T>::type>::value ||
std::is_same<char *, typename std::decay<T>::type>::value
> {};
Estoy tratando de escribir una plantilla is_c_str para probar si un tipo es una cadena de estilo c. Necesito esto como un intento de escribir una función to_string, como se muestra en mi otra pregunta aquí: ¿ Especialización de plantillas para iteradores de contenedores STL? .
Necesito distinguir c_str y otros tipos de punteros e iteradores, para poder representar el primero en el valor nominal, y representar los punteros / iteradores como un "itor" o "ptr" opaco. El código es el siguiente:
#include <iostream>
template<class T>
struct is_c_str
: std::integral_constant<
bool,
!std::is_same<char *, typename std::remove_reference<typename std::remove_cv<T>::type>::type>::value
> {};
int main() {
auto sz = "Hello"; //Or: const char * sz = "Hello";
int i;
double d;
std::cout << is_c_str<decltype(sz)>::value << ", "
<< is_c_str<decltype(i)>::value << ", "
<< is_c_str<decltype(d)>::value << std::endl;
}
Sin embargo, is_c_str captura no solo const char * , sino también int y double . Las salidas del código anterior:
1, 1, 1
(a partir de gcc-4.8.1).
¿Mi pregunta es cómo arreglar is_c_str para capturar correctamente las cadenas de estilo c?
El tipo de sz es char const* , pero std::remove_cv<> solo elimina la const nivel superior, por lo que no puede obtener char* través de su aplicación. En su lugar, simplemente puede buscar una char const* después de descomponer completamente el tipo con std::decay<> :
namespace detail
{
template<class T>
struct is_c_str : std::is_same<char const*, T> {};
}
template<class T>
struct is_c_str : detail::is_c_str<typename std::decay<T>::type> {};
int main() {
auto sz = "Hello";
int i;
double d;
std::cout << is_c_str<decltype(sz)>::value << ", "
<< is_c_str<decltype(i)>::value << ", "
<< is_c_str<decltype(d)>::value << std::endl;
}
También estabas negando falsamente la condición. Yo también arreglé eso.
Hay un par de problemas.
La línea
!std::is_same<char *, typename std::remove_reference<typename std::remove_cv<T>::type>::type>::valuenecesita ser
std::is_same<char *, typename std::remove_reference<typename std::remove_cv<T>::type>::type>::valueSu lógica de usar
typename std::remove_reference<typename std::remove_cv<T>::type>::type>::valuees defectuosa. No conviertechar const*achar*. Puede convertirchar* constachar*.
Lo que necesitas es:
template<class T>
struct is_c_str
: std::integral_constant<
bool,
std::is_same<char *, typename std::remove_reference<typename std::remove_cv<T>::type>::type>::value ||
std::is_same<char const*, typename std::remove_reference<typename std::remove_cv<T>::type>::type>::value
> {};
Intenté esto y parece funcionar:
#include <iostream>
template<class T>
struct is_c_str : std::integral_constant<bool, false> {};
template<>
struct is_c_str<char*> : std::integral_constant<bool, true> {};
template<>
struct is_c_str<const char*> : std::integral_constant<bool, true> {};
int main() {
auto sz = "Hello";
int i;
double d;
std::cout << is_c_str<decltype(sz)>::value << ", "
<< is_c_str<decltype(i)>::value << ", "
<< is_c_str<decltype(d)>::value << std::endl;
}
Obviamente, enumerar todos los casos no es tan elegante como poner el predicado general en std:integral_constant , pero, por otro lado, ese predicado es una lengua extraña para idiotas como yo, mientras que la especialización de plantillas de "fuerza bruta" es algo más comprensible y viable en este sentido. Caso como hay pocas especializaciones.
Ya hay algunas soluciones, pero como la solución más simple es realmente simple, la anotaré aquí.
template< typename, typename = void >
struct is_c_str
: std::false_type {};
template< typename t >
struct is_c_str< t *,
typename std::enable_if< std::is_same<
typename std::decay< t >::type,
char
>::value >::type
>
: std::true_type {};
La parte difícil, por supuesto, es analizar qué hay dentro del tipo de puntero en lugar del tipo de puntero en sí.