c++ templates specialization

c++ - ¿Especialización en plantillas parciales basada en la "firma-ness" de tipo entero?



templates specialization (5)

¿Hay alguna forma inteligente de no hacer la comparación n> = 0 cuando T es un tipo sin firma? Intenté agregar una especialización de plantilla parcial:

El optimizador debería descartar el código para la comparación, ya que detectó la condición.

Para Clang, agregue -Wno-tautological-compare para aplastar la advertencia. Para GCC / G ++, agregue -Wno-type-limits para aplastar la advertencia.

Si está utilizando un compilador que soporta pragma diagnostic {push|pop} puede:

#if (GCC_VERSION >= 40600) || (LLVM_CLANG_VERSION >= 10700) || (APPLE_CLANG_VERSION >= 20000) # define GCC_DIAGNOSTIC_AVAILABLE 1 #endif #if MSC_VERSION # pragma warning(push) # pragma warning(disable: 4389) #endif #if GCC_DIAGNOSTIC_AVAILABLE # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wsign-compare" # if (LLVM_CLANG_VERSION >= 20800) || (APPLE_CLANG_VERSION >= 30000) # pragma GCC diagnostic ignored "-Wtautological-compare" # elif (GCC_VERSION >= 40300) # pragma GCC diagnostic ignored "-Wtype-limits" # endif #endif template<typename T> inline bool f( T n ) { return n >= 0 && n <= 100; } #if GCC_DIAGNOSTIC_AVAILABLE # pragma GCC diagnostic pop #endif #if MSC_VERSION # pragma warning(pop) #endif

Ver también La comparación siempre es falsa debido a un rango limitado ...

Dado:

template<typename T> inline bool f( T n ) { return n >= 0 && n <= 100; }

Cuando se usa con un tipo unsigned genera una advertencia:

unsigned n; f( n ); // warning: comparison n >= 0 is always true

¿Hay alguna forma inteligente de no hacer la comparación n >= 0 cuando T es un tipo unsigned ? Intenté agregar una especialización de plantilla parcial:

template<typename T> inline bool f( unsigned T n ) { return n <= 100; }

pero a gcc 4.2.1 no le gusta eso. (No pensé que ese tipo de especialización de plantilla parcial sería legal de todos modos).


Comenzando en c ++ 17 con la introducción de if constexpr ni siquiera necesita proporcionar especializaciones para esto. A diferencia de una sentencia if normal, el código en el if constexpr se descartará (no se compilará) si la expresión no es verdadera. Eso significa que puedes reescribir tu función como

template<typename T> inline bool f( T n ) { if constexpr (std::is_unsigned_v<T>) return n <= 100; else return n >= 0 && n <= 100; }


Puede aprovechar el comportamiento envolvente de los enteros sin signo.

template<bool> struct bool_ { }; template<typename T> inline bool f( T n, bool_<false> ) { return n >= 0 && n <= 100; } template<typename T> inline bool f( T n, bool_<true> ) { return n <= 100; } template<typename T> inline bool f( T n ) { return f(n, bool_<(static_cast<T>(-1) > 0)>()); }

Es importante no decir >= 0 , para evitar una advertencia de nuevo. Lo siguiente parece engañar a GCC también

template<typename T> inline bool f( T n ) { return (n == 0 || n > 0) && n <= 100; }


Puede implementar una implementación de función de plantilla especial para un tipo unsigned como:

template<class T> bool f(T val); template<> bool f<unsigned>(unsigned val);

ACTUALIZAR bandera sin firmar

Puede implementar diferentes implementaciones para todos los tipos sin firma que le gustaría usar o agregar un indicador bool como:

template <class T, bool U> bool f(T val) { if (U) return val <= 100; else return (val >=0 ) && (val <= 100); } ... cout << f<int, false>(1) << endl; cout << f<int, false>(-1) << endl; cout << f<char, true>(10) << endl;


Puede usar enable_if con el rasgo de tipo is_unsigned :

template <typename T> typename std::enable_if<std::is_unsigned<T>::value, bool>::type f(T n) { return n <= 100; } template <typename T> typename std::enable_if<!std::is_unsigned<T>::value, bool>::type f(T n) { return n >= 0 && n <= 100; }

Puede encontrar enable_if y is_unsigned en los std::tr1 nombres std o std::tr1 si su compilador admite C ++ 0x o TR1, respectivamente. De lo contrario, Boost tiene una implementación de la biblioteca de rasgos de tipo, Boost.TypeTraits . La implementación de enable_if de enable_if es un poco diferente; boost::enable_if_c es similar a TR1 y C ++ 0x enable_if .