Initialize integer literal to std::size_t
There are known ways to manipulate the type of an integer literal
0L; // long
3U; // unsigned integer
1LL; // long long
What I need is a way to initialize an integer literal to std::size_t
. I supposed that doing
2U; // unsigned int
would be enough, but I still get a compiler error when calling a function template that expects two arguments of the same integral type (no matching function to call for func(unsigned int, size_t
)
I know/verified that explicitly casting ( static_cast<std::size_t>(1)
) the first argument solves the problem but I'm asking if there's a prettier solution
EDIT
the function has a signature
template <class T> const T& func(const T& a, const T& b);
EDIT2
I don't know if this question is to "blame" but I'm happy to announce that this is upcoming (cudos @malat for mentioning this in the comments)
There is no such standard facility. C99 and C++11 implementations do have such macros in <stdint.h>
/<cstdint>
. But even there, the macros are only defined for the stdint.h
types, which do not include size_t
.
You could define a user-defined literal operator:
constexpr std::size_t operator "" _z ( unsigned long long n )
{ return n; }
auto sz = 5_z;
static_assert( std::is_same< decltype( sz ), std::size_t >::value, "" );
The constexpr
is necessary to use it in array bounds int arr[ 23_z ]
or case 9_z:
labels.
Most would probably consider the lack of macros to be an advantage :) .
Cuteness aside, the best way is to use brace initialization: std::size_t{ 42 }
. This is not equivalent to std::size_t( 42 )
which is like a nasty C cast — presumably what you were avoiding with static_cast
. Quite the opposite: the braces require that the value inside is exactly representable in the targeted type. So, char{ 300 }
and std::size_t{ -1 }
are both ill-formed.
Braces and parens look similar, but they're polar opposites in safety when initializing temporaries. Braces are safer than the literal operator could ever be, since unlike a function they can discriminate compile-time values.
There is no dedicated suffix for std::size_t
. In C++11, you could create a user-defined literal for it, though:
std::size_t operator "" _sz (unsigned long long int x)
{
return x;
}
// Usage:
auto s = 1024_sz;
static_assert(std::is_same<decltype(s), std::size_t>::value, "He's wrong");
Live example
Starting from C++23 you can use the uz
or UZ
literal for size_t
.
auto size = 42uz;
static_assert(std::is_same_v<decltype(size), std::size_t>);
Paper: P0330R8
cppreference: Integer literals
Depending on the function, you may also be able to do this and may find it cleaner:
auto result = func<size_t>(1, some_var);
For example, I've done this with std::max
:
auto result = std::max<size_t>(0, std::min<size_t>(index, vec.size()-1));
By explicitly specifying the template instantiation, the casts can be implicit. However, do note that this is a cast, so is susceptible to errors which Potatoswatter's brace initialization isn't.