es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

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,>

Tags:  , ,

Answer

  1. Avatar for 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 de constexpr. Una posible solución es usar static_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:
    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(a) + static_cast(b) >= static_cast(a);
    }
    };

    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 como unsigned int), sumándolos y luego verificando si el resultado es mayor o igual al valor original a. La función devuelve true si no hay desbordamiento y false en caso contrario.

    La función operator+ ahora llama a check_overflow para verificar que no haya desbordamiento antes de devolver el resultado de la adición. La palabra clave constexpr 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,>

Comments are closed.