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
.