Implementación de clang de __builtin_add_overflow_p
Estoy experimentando con una clase de C++ similar a std::integral_constant
con dos diferencias principales: primero, no admite operator()
ni ningún operador de conversión. Dos, admite operadores de no modificación como operator+
, y mi objetivo es que verifique la seguridad de estos operadores en tiempo de compilación. Encontré estos útiles builtins que GCC admite. Entonces puedo hacer lo siguiente:
template <typename t,="" t="" val="">
class literal
{
public:
template <t t="">
literal<t, val="" +="" t=""> consteval operator+(attribute((unused)) const literal<t, t=""> &other) const
{
static_assert(!__builtin_add_overflow_p(val, t, static_cast<t>(0)));
return { };
}
};
constexpr literal<unsigned int,=""></unsigned><unsigned int="">::max()> x, y;
x + y; // <- esto es capturado por static_assert en tiempo de compilación!
Pero resulta que clang no admite __builtin_add_overflow_p
. Sí tiene __builtin_add_overflow
, pero no es constexpr
y, por lo tanto, no se puede utilizar en tiempo de compilación. ¿Existe alguna manera de resolver esto para que este código funcione con clang?</t,></t,>
davy.ai
Como
__builtin_add_overflow_p
no es compatible con clang en tiempo de compilación, se necesita un enfoque alternativo para verificar el desbordamiento de enteros en un contexto deconstexpr
. Una posible solución es usarstatic_cast
a un tipo más grande y verificar el desbordamiento allí. Esto se puede lograr creando una función miembro estática en la clase que realiza la adición y verifica el desbordamiento. Este enfoque no depende de ninguna construcción específica del compilador y, por lo tanto, es más portátil.Aquí hay una clase
literal
actualizada que utiliza este enfoque:“`c++
template
class literal
{
public:
template
constexpr literal<t, val=”” +=”” t=””> operator+(const literal<t, t=””>&) const
{
static_assert(check_overflow(val, t));
return {};
}
private:(a) + static_cast (b) >= static_cast (a);
template
static constexpr bool check_overflow(U a, U b)
{
using larger_type = std::conditional_t<(sizeof(T) < sizeof(U)), U, T>;
return static_cast
}
};
constexpr literal::max()> x, y;
x + y; // esto será detectado por static_assert
“`
En esta versión actualizada, la función
check_overflow
verifica el desbordamiento mediante la conversión de los valores de entrada a un tipo más grande (en este caso,unsigned long long
, que tiene garantizado ser al menos tan grande comounsigned int
), sumándolos y luego verificando si el resultado es mayor o igual al valor originala
. La función devuelvetrue
si no hay desbordamiento yfalse
en caso contrario.La función
operator+
ahora llama acheck_overflow
para verificar que no haya desbordamiento antes de devolver el resultado de la adición. La palabra claveconstexpr
se utiliza para indicar que esta función se puede evaluar en tiempo de compilación.Con este enfoque, el código funcionará tanto con GCC como con clang, y detectará los desbordamientos de enteros en tiempo de compilación.</t,></t,>