Adam W
Adam W

Reputation: 337

static_assert each parameter's size in parameter pack

I am trying to check whether each parameter within a parameter pack can be stored within 8 bytes (sizeof <= 8)

I have the function signature:

template <typename Return, typename... Arguments>
inline auto invoke(std::uint64_t hash, Arguments... arguments) -> Return

Using fold expressions, I have tried:

static_assert((sizeof(arguments) <= 8 && ...));

Which failed to compile with unexpected token '...', expected 'expression' - I assume it's invalid or incorrect?

Using C++20 concepts and constraints, I assume something along the lines of is possible?

template <typename Return, typename... Arguments> requires (sizeof(arguments) <= 8 || ...)
inline auto invoke(std::uint64_t hash, Arguments... arguments) -> Return

I assume there is a way of using the standard library to say check that a type fits within a std::uint64_t say also?

Upvotes: 1

Views: 495

Answers (2)

Feng Wang
Feng Wang

Reputation: 1594

Try this way:

#include <cstdint>
#include <utility>
template <typename... Arguments>
auto invoke(std::uint64_t hash, Arguments... arguments)
{
    auto check = []( auto&& argument )
    {
        static_assert( sizeof(argument) <= 8, "size too large" );
        return 0;
    };
    auto dummy = { 0, ( check(std::forward<Arguments>(arguments)), 0) ... };
    return 0;
}

int main()
{
    invoke( 0UL, '1' );
    invoke( 0UL, '1', 2 );
    invoke( 0UL, '1', 2, 3UL );
    //invoke( 0UL, '1', 2, 3UL, static_cast<long double>(1.0) );
    return 0;
}

Using the comma operator and the initializer_list to do the trick.

With C++17, we can further trim the code to:

template <typename... Arguments>
auto invoke(std::uint64_t hash, Arguments... arguments)
{
    auto check = []( auto&& argument )
    {
        static_assert( sizeof(argument) <= 8, "size too large" );
    };
    (check(std::forward<Arguments>(arguments)), ...);
}

taking the advantage of fold expressions.


I do not understand the downvotes, but as this is my last post in stackoverflow, I uploaded a live example at wandbox: https://wandbox.org/permlink/NZbqpRaTs2TFOCwG

Upvotes: -2

Daniel Langr
Daniel Langr

Reputation: 23527

With C++20 concepts, there are many ways how to achieve the desired behavior. For instance:

template <typename T, size_t N>
concept bool SizeLessEqual = sizeof(T) <= N;

template <SizeLessEqual<8>... Types>
void f() { }

int main() {
    f<bool, char, int, double>();
    f<std::string>();  // error
}

Live demo: https://wandbox.org/permlink/Q9tifNVplsx9BjGN

Another option is your solution:

template <typename... Types> requires ((sizeof(Types) <= 8) && ...) 
void f() { }

Or, e.g.:

template <typename... Types> requires (std::max({ sizeof(Types)... }) <= 8) 
void f() { }

Upvotes: 3

Related Questions