sintaxis programas estructuras ejemplos dev definicion curso comandos c++ templates c++11 typetraits

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.

Ejemplo vivo


Hay un par de problemas.

  1. La línea

    !std::is_same<char *, typename std::remove_reference<typename std::remove_cv<T>::type>::type>::value

    necesita ser

    std::is_same<char *, typename std::remove_reference<typename std::remove_cv<T>::type>::type>::value

  2. Su lógica de usar typename std::remove_reference<typename std::remove_cv<T>::type>::type>::value es defectuosa. No convierte char const* a char* . Puede convertir char* const a char* .

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