Fiz alguns modelos que supostamente
- (1) testar se os números podem ser adicionados sem estouro,
- (2) somar números e falhar em caso de estouro.
O (1) test_sum
dentro static_assert
compila, então acho que é constexpr
.
Eu queria evitar duplicar os cálculos, então tentei colocar a declaração diretamente dentro da função (2) que calcula a soma. No entanto, a declaração sempre falha, independentemente da condição, em todas as versões abaixo. Isso pode ser resolvido de alguma forma?
#include <limits>
#include <stdexcept>
#include <type_traits>
template<typename T>
constexpr bool add(T& a, T b)
{
static_assert(std::is_integral<T>::value, "Only integral types are supported");
if ((b > 0) && (a > std::numeric_limits<T>::max() - b))
return false;
if ((b < 0) && (a < std::numeric_limits<T>::min() - b))
return false;
a += b;
return true;
}
//
template<typename T>
constexpr bool sum_impl(T& result)
{
return true;
}
template<typename T, typename... Rest>
constexpr bool sum_impl(T& result, T value, Rest... rest)
{
if (!add(result, value))
return false;
return sum_impl(result, rest...);
}
//
template<typename T, typename... Rest>
constexpr bool test_sum(T value, Rest... rest) // (1)
{
return sum_impl(value, rest...);
}
template<typename T, typename... Rest>
T sum(T value, Rest... rest) // (2) regular
{
if (!sum_impl(value, rest...))
throw std::overflow_error("Overflow in checked::sum");
return value;
}
template<typename T, typename... Rest>
constexpr T sum_cexpr(T value, Rest... rest) // (2) constexpr
{
// if (!sum_impl(value, rest...))
// static_assert(false, "Overflow"); // fail
// static_assert(sum_impl(value, rest...), "Overflow"); // fail
// if (!sum_impl(value, rest...))
// delegated_assert<false>(); // fail
return value;
}
template<bool B>
constexpr void delegated_assert()
{
if constexpr (!B)
static_assert(B);
}
//////
int main()
{
static_assert(test_sum(1, 2)); // (1) works
constexpr int a = sum_cexpr(10, 20, 30); // fails to compile
return 0;
}