views:

211

answers:

5

Static asserts are very convenient for checking things in compile time. A simple static assert idiom looks like this:

template<bool> struct StaticAssert;
template<> struct StaticAssert<true> {};

#define STATIC_ASSERT(condition) do { StaticAssert<(condition)>(); } while(0)

This is good for stuff like

STATIC_ASSERT(sizeof(float) == 4)

and:

#define THIS_LIMIT (1000)
...
STATIC_ASSERT(THIS_LIMIT > OTHER_LIMIT);

But using #define is not the "C++" way of defining constants. C++ would have you use an anonymous namespace:

namespace {
    const int THIS_LIMIT = 1000;
}

or even:

static const int THIS_LIMIT = 1000;

The trouble with this is that with a const int you can't use STATIC_ASSERT() and you must resort to a run-time check which is silly.

Is there a way to properly solve this in current C++?
I think I've read C++0x has some facility to do this...


EDIT

Ok so this

static const int THIS_LIMIT = 1000;
...
STATIC_ASSERT(THIS_LIMIT > 0);

compiles fine
But this:

static const float THIS_LIMIT = 1000.0f;
...
STATIC_ASSERT(THIS_LIMIT > 0.0f);

does not.
(in Visual Studio 2008)

How come?

+9  A: 

Why, you can still static assert with const int:

#define static_assert(e) extern char (*ct_assert(void)) [sizeof(char[1 - 2*!(e)])]
static_assert( THIS_LIMIT > OTHER_LIMIT )

Also, use boost!

BOOST_STATIC_ASSERT( THIS_LIMIT > OTHER_LIMIT )

... you'll get a lot nicer error messages...

Kornel Kisielewicz
Well, there's a lesson for me. don't say something isn't possible before trying it...
shoosh
I still wonder what problem that is supposed to fix?
Georg Fritzsche
@shoosh: You original code should compile fine. See [my reply](http://stackoverflow.com/questions/2902917/2903013#2903013).
sbi
@Georg, I just posted the one I use in lack of boost -- it's advantage is that it doesn't have to be in function scope. As for error readability -- depends on the compiler.
Kornel Kisielewicz
@sbi: Ah, no problem. @Kornel: Maybe its only me, but i read it as *"use this instead, otherwise it won't work"*, you don't mention that the OPs original approach already worked.
Georg Fritzsche
+1  A: 

Perhaps you're confusing C++'s behavior with C, where const int does not represent a true compile-time constant. Or perhaps your C++ compiler is broken. If it's truly the latter, use enum instead.

jamesdlin
you got +1, i got -1 for the same solution =/
Viktor Sehr
@Viktor Sehr: To be fair, my answer provides mores explanation than yours, and using `enum` should *not* be necessary in C++ for this case.
jamesdlin
+1  A: 

This:

namespace {
    const int THIS_LIMIT = 1000;
}

template<bool> struct StaticAssert;
template<> struct StaticAssert<true> {};

#define STATIC_ASSERT(condition) do { StaticAssert<(condition)>(); } while(0)

int main()
{
    STATIC_ASSERT(THIS_LIMIT > 5);

    return (0);
}

compiles fine with VC and Comeau.

sbi
A: 

enum{THIS_LIMIT = 1000};

Viktor Sehr
Why the -1 vote?
Viktor Sehr
+2  A: 

static_assert is a compiler feature in C++0x so as long as you've got a relatively up-to-date compiler you can use that. Watch out for doing #define static_assert(x) ..., because it's a real keyword in C++0x so you'd be permanently hiding the compiler feature. Also, C++0x static_assert takes two parameters (eg. static_assert(sizeof(int) == 4, "Expecting int to be 4 bytes")), so you could cause yourself problems trying to switch in future if you use that #define.

AshleysBrain