I made some templates which are supposed to
- (1) test if numbers can be added without overflow,
- (2) add numbers and fail in case of overflow.
The (1) test_sum inside static_assert compiles, so I guess it is constexpr.
I wanted to avoid duplicating the math, so I tried to put the assert directly inside the (2) function that calculates the sum.
However, the assert always fails, no matter the condition, in all the versions below. Can this be solved in any way?
#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;
}
test_suminsidestatic_assertcompiles" That's not present in the code shown. It never callstest_sum, understatic_assertor otherwise.