Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Cause error if integral parameter too large

32 views
Skip to first unread message

Juha Nieminen

unread,
Sep 10, 2020, 5:02:22 AM9/10/20
to
Suppose I have something like this:

//---------------------------------------------------
#if SOME_CONDITION
void func(std::uint64_t);
#else
void func(std::uint32_t);
#end
//---------------------------------------------------

and I would want it so that if it's the latter function that's being
declared, if it gets called with an integral value that's too large
(eg. a std::uint64_t or std::int64_t), a compiler error happens
(eg. with a static_assert).

In other words, if it's the second function above that's defined,
it can only be called with an 32-bit integer or smaller. If you want
to call it with a larger variable, you'll have to use an explicit cast.

In other words, if you try to do something like:

//---------------------------------------------------
std::uint64_t value = 5;
func(value); // static_assert triggers
func(static_cast<uint32_t>(value)) // ok
//---------------------------------------------------

What would be the best way to achieve this?

Note that something like this isn't good:

//---------------------------------------------------
void func(std::uint32_t);
inline void func(std::uint64_t) { static_assert(false, "explanation"); }
//---------------------------------------------------

because that causes errors with ambiguous parameters, like if you were to
call it like:

//---------------------------------------------------
func(10); // This should be a-ok, but with the above it causes an error
//---------------------------------------------------

alrote

unread,
Sep 10, 2020, 7:29:32 AM9/10/20
to


inline void func(std::uint64_t &) { static_assert(false, "explanation");

Paavo Helde

unread,
Sep 10, 2020, 8:13:38 AM9/10/20
to
10.09.2020 12:01 Juha Nieminen kirjutas:
> Suppose I have something like this:
>
> //---------------------------------------------------
> #if SOME_CONDITION
> void func(std::uint64_t);
> #else
> void func(std::uint32_t);
> #end
> //---------------------------------------------------
>
> and I would want it so that if it's the latter function that's being
> declared, if it gets called with an integral value that's too large
> (eg. a std::uint64_t or std::int64_t), a compiler error happens
> (eg. with a static_assert).
>
> In other words, if it's the second function above that's defined,
> it can only be called with an 32-bit integer or smaller. If you want
> to call it with a larger variable, you'll have to use an explicit cast.
>
> In other words, if you try to do something like:
>
> //---------------------------------------------------
> std::uint64_t value = 5;
> func(value); // static_assert triggers
> func(static_cast<uint32_t>(value)) // ok
> //---------------------------------------------------

It is not clear if you want a compile-time error with a too large value
or a too large type.

To get a compile-time error for a too large value the value must be a
compile-time constant itself, so it can appear e.g. as a template
parameter and can be easily checked by static_assert:

#include <cstdint>
#include <limits>

#define SOME_CONDITION 0

#if SOME_CONDITION
template<std::uint64_t x>
void func() {}
#else
template<std::uint64_t x>
void func() {
static_assert(x<=std::numeric_limits<std::uint32_t>::max(), "Value
too large");
}
#endif

int main() {
func<0xffffffffffff>(); // compile error: Value too large
func<10>(); // ok
}

To get a compile-time error for larger types is also easy:

#include <cstdint>
#include <type_traits>

#define SOME_CONDITION 0

#if SOME_CONDITION

void func(std::uint64_t x) {}

#else

template<typename T,
typename = typename std::enable_if<sizeof(T)<=4>::type>
void func(T x0) {
std::uint32_t x = static_cast<std::uint32_t>(x0);
// ...
}
#endif

int main() {
std::uint64_t a = 10;
int b = -5;
func(a); // compile error: 'func': no matching overloaded function found
func(b); // ok
}







Sam

unread,
Sep 10, 2020, 8:33:27 AM9/10/20
to
template<typename T, typename=uint32_t_or_less_t<std::remove_reference_t<T>>>
void func(T &&v)
{
real_func(std::forward<T>(v));
}

Just one more piece: a uint32_t_or_less_t template that resolves only for
integral types that are uint32_t or less. Fairly straightforward, no need to
spell it out.


Keith Thompson

unread,
Sep 10, 2020, 3:57:31 PM9/10/20
to
Yes, it is clear from the example quoted above:

std::uint64_t value = 5;
func(value); // static_assert triggers

[...]

--
Keith Thompson (The_Other_Keith) Keith.S.T...@gmail.com
Working, but not speaking, for Philips Healthcare
void Void(void) { Void(); } /* The recursive call of the void */

Alf P. Steinbach

unread,
Sep 10, 2020, 6:37:03 PM9/10/20
to
The following is possibly what you want.

The possible error message mentions that the function is deleted, and
I'd hoped it would also mention the condition where it is deleted, but
alas, both g++ and MSVC fail to include that in the diagnostic.

It's /possible/ that instead of this functionality you really intended
what you get with the out-commented definition of `has_all_values_of_? .



---------------------------------------------------------------------------
#include <limits.h> // CHAR_BIT
#include <stdint.h> // uint32_t, uint64_t

#include <utility>
using std::enable_if_t, std::is_integral_v, std::is_signed_v;

// template< class A, class B >
// constexpr bool has_all_values_of_ = true
// and (is_integral_v<A> and is_integral_v<B>)
// and (is_signed_v<A> == is_signed_v<B>? sizeof( A ) <= sizeof( B
) : sizeof( A ) < sizeof( B ));

template< class A, class B >
constexpr bool has_all_values_of_ = true
and is_integral_v<A> and is_integral_v<B> and sizeof( A ) <=
sizeof( B );

#if 0
using Word = uint64_t;
#else
using Word = uint32_t;
#endif

void func( const Word ) {}

template< class T, class = enable_if_t<not has_all_values_of_<T, Word>> >
void func( const T ) = delete;

auto main() -> int
{
func( Word( 1 ) ); // OK
func( 'A' ); // OK
func( 1 ); // OK with the uncommented definition of
`has_all_values_of_`.

func( 0LL ); //! Oh noes.
}
---------------------------------------------------------------------------


- Alf
0 new messages