Is std::size_t a distinct type?

2.4k Views Asked by At

The C++ standard mentions this for std::size_t:

The type size_t is an implementation-defined unsigned integer type that is large enough to contain the size in bytes of any object ([expr.sizeof]).

Now my question is that if this type is a distinct type from other unsigned int types or not. I mean, should I be able to have overloads like this or not:

void myfunc(std::uint16_t) {}
void myfunc(std::uint32_t) {}
void myfunc(std::uint64_t) {}
void myfunc(std::size_t) {}

Because if it is a distinct type, I should be able to have these overloads while if it is not, I should get redefinition error. I somehow always thought that std::size_t should be a distinct type but I currently get redefinition error which means it is not (at least in GCC and Clang)

The reason that I'm asking this is that I want to know if I have overload of a function for different unsigned int sizes, can I safely assume that one of them will be called for std::size_t or not.

3

There are 3 best solutions below

5
user17732522 On BEST ANSWER

Now my question is that if this type is a distinct type from other unsigned int types or not.

Your question heavily depends on what exactly you mean with "unsigned int types". I'll assume this to refer to "unsigned integer types" as defined by the standard.

It can not be a type distinct from other unsigned integer types. All unsigned integer types are listed exclusively in [basic.fundamental]/2. These are the standard unsigned integer types unsigned char, unsigned short, unsigned int, unsigned long and unsigned long long, and extended unsigned integer types if the implementation defines any (which isn't usually the case in the most common C++ implementations).

If you intend "unsigned int types" to refer to the standard unsigned integer types listed above, then the answer becomes that size_t is neither required, nor prohibited, to be one of them, since it may also be one of the extended unsigned integer types. But if the implementation has none of those, then it must be one of the standard unsigned integer types.

If you intend "unsigned int types" to mean any "integer types" as defined in the standard which also have unsigned signdness, then the answer is again that it cannot be distinct from this set, since this set merely is a superset of the set of all unsigned integer types, adding char8_t, char16_t, char32_t and potentially char and wchar_t (which have implementation-defined signdness).

(You can find definitions for all the mentioned terms from the standard in [basic.fundamental]/1 to 11 of the post-C++20 ISO C++ draft N4868 I linked above.)


Because if it is a distinct type, I should be able to have these overloads while if it is not, I should get redefinition error.

Regardless of the above, it is not guaranteed to cause a redefinition error, because while the types uint16_t, uint32_t and uint64_t also must be unsigned integer types from the same category, they don't have to cover the whole category and in fact cannot, because there are at least 5 unsigned integer types, but you listed only three uintX_t overloads. So size_t doesn't need to match any of them and in fact doesn't need to match any uintX_t at all.

For example on 64bit architectures, often uint16_t is unsigned short, uint32_t is unsigned int and uint64_t is either unsigned long or unsigned long long, with the remaining one not being aliased by any uintX_t.

So the overload set is not safe. size_t may be one of the uintX_t or it may not and neither the whole uintX_t set, nor the whole set including size_t must cover the set of all unsigned integer types.

If you want to overload for all unsigned integer types, overload by the actual (non-alias) type names for the standard unsigned integer types listed above, as well as all extended unsigned integer types if your implementation has them. However, consider whether a template, possibly constrained with a type trait, isn't a better option instead, since you can't portably know about extended integer types.

3
Vlad from Moscow On

The C++ header <cstddef> in fact is same as the C <stddef.h>.

From the C++17 Standard

1 The contents and meaning of the header are the same as the C standard library header <stdlib.h>, except that it does not declare the type wchar_t, and except as noted in 21.2.3, 21.2.4, 21.5, 23.10.11, 24.5.6, 28.8, 29.6.9, and 29.9.2.

In C the name size_t is defined as a macro

7.19 Common definitions <stddef.h>

1 The header <stddef.h> defines the following macros and declares the following types. Some are also defined in other headers, as noted in their respective subclauses. 2 The types are

ptrdiff_t 

which is the signed integer type of the result of subtracting two pointers;

size_t

which is the unsigned integer type of the result of the sizeof operator;

Usually size_t is defined as an alias for the type unsigned long.

4 The types used for size_t and ptrdiff_t should not have an integer conversion rank greater than that of signed long int unless the implementation supports objects large enough to make this necessary

0
Yakk - Adam Nevraumont On

No; there is no fixed list of types that don't mention size_t that is guaranteed by the standard to include size_t.

The reason that I'm asking this is that I want to know if I have overload of a function for different unsigned int sizes, can I safely assume that one of them will be called for std::size_t or not.

Yes, you can make this guarantee.

Simply add

static_assert( size_t is one of (your fixed list) )

There are 3 major compilers. You can learn how those 3 do this problem, and make a list of overloads that work for those compilers (possibly including #ifdef based tests; I honestly doubt it is needed).

Then you static_assert that your list contains `size_t.

In the event that your research becomes obsolete, your static assert fires. Include a comment on what you should do in this case.

There are many ways to write that static assert. The tricky part is making sure that your list of overloads matches the list of types there; I don't know of a clean way to do that.

If you are willing to make these overloads members (even static members) of a class, you can use template metaprogramming to make the overloads and do the size_t check. It could even have a list of integers and conditionally add size_t if it isn't there, rather than check.