1

I was thinking one of these:

#if sizeof(size_t) == 8
const size_t foo = 12345;
#elif sizeof(size_t) == 4
const size_t foo = 123;
#else
#error "Unsupported size_t size"
#endif

or

template <int S> class Foo { static const size_t foo = 0; };
template <> class Foo<8> { static const size_t foo = 12345; };
template <> class Foo<4> { static const size_t foo = 123; };
const size_t foo = Foo<sizeof(size_t)>::foo;

Also, how can I throw a compile-time error using the second method?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Matt
  • 21,026
  • 18
  • 63
  • 115
  • 6
    You can use `std::static_assert` in the second method. – Kevin Jan 24 '15 at 00:11
  • 3
    `#if` does not know about `sizeof`. You could use some of the macros from `limits.h` though, e.g. `SIZE_MAX`. – M.M Jan 24 '15 at 00:13
  • @MattMcNabb That's a good point, I forgot about that. And `SIZE_MAX` would only work if it is in fact `size_t` (or one of the other standard types) that I care about, which is not necessarily the case. – Matt Jan 24 '15 at 00:14
  • Do the values follow some logic or are they arbitrary? Take a look at `numeric_limits` – Neil Kirk Jan 24 '15 at 01:17
  • @NeilKirk, they follow some logic, but the logic is too complicated for compile-time calculations. Definitely not something `numeric_limits` can solve. At the present moment, I'm dealing with assigning a suitably large prime number for 32-bit and 64-bit integer types. – Matt Jan 24 '15 at 01:22

3 Answers3

4

The solution with the class template is a good idiomatic way of doing this (the first alternative would also not work, so it's no contest between these two candidates).

To cause a compile-time error, simply do not define the template for all sizes:

template <int S> class Foo;

The compiler will then complain that the template is not defined for the offending value of sizeof(size_t).

It would also help to change the name from Foo to something like Environment_Where_sizeof_int_is -- you 'd get more immediately understandable compiler errors in practice.

Jon
  • 428,835
  • 81
  • 738
  • 806
  • Thanks, but that doesn't answer my main question. – Matt Jan 24 '15 at 00:18
  • 2
    @Matt: I edited to explicitly address it, although of course the core of the answer remains unchanged. – Jon Jan 24 '15 at 00:20
  • Just for the record, I only use names like `Foo` in examples. – Matt Jan 24 '15 at 00:23
  • 1
    @Matt: His point wasn't that `Foo` is wrong, his point was that the name of `Foo` can be "abused" to show clearer error messages for the case where it doesn't exist: http://coliru.stacked-crooked.com/a/77b9faf649bd712f `error: incomplete type 'Environment_Where_sizeof_int_is<3>' used in nested name specifier` – Mooing Duck Jan 24 '15 at 00:32
1

With g++ you can also use the following predefined macros:

__SIZEOF_SIZE_T__
__SIZEOF_INT__
__SIZEOF_LONG__

(and so on for the other types, see the documentation for a complete list).

For example:

#if __SIZEOF_SIZE_T__ == 8
const size_t foo = 12345;
#elif __SIZEOF_SIZE_T__ == 4
const size_t foo = 123;
#else
#error "Unsupported size_t size"
#endif
ouah
  • 142,963
  • 15
  • 272
  • 331
  • Thanks, but as I pointed out in the comments, the type in question is not necessarily one of the standard types. – Matt Jan 24 '15 at 00:39
  • 1
    @Matt I actually didn't read the comments. My answer is also not Standard C++ but for those who don't know this I think it can help. – ouah Jan 24 '15 at 00:41
0

Use the type for the first and second member of a defined structure and get the offset of the second member to get the size of the first member (this assumes no padding between first and second member, the first member is guaranteed to have the same address as the structure).

#define ofs(s,m)   (size_t)&(((s *)0)->m)

typedef struct S_{
size_t a;       /* type to get the size of */
size_t b;       /* make this same type as above */
}S;

int main()
{
size_t c;
    c = ofs(S,b);   /* get size of S.a */
    return(0);
}
rcgldr
  • 27,407
  • 3
  • 36
  • 61