views:

81

answers:

3
const int bob = 0;

if(bob)
{
    int fred = 6/bob;
}

you will get an error on the line where the divide is done: "error C2124: divide or mod by zero"

which is lame, because it is just as inevitable that the 'if' check will fail, as it is the divide will result in a div by 0. quite frankly I see no reason for the compiler to even evaluate anything in the 'if', except to assure brace integrity.

anyway, obviously that example isn't my problem, my problem comes when doing complicated template stuff to try and do as much at compile time as possible, in some cases arguments may be 0.

is there anyway to fix this error? or disable it? or any better workarounds than this:

currently the only work around I can think of (which I've done before when I encountered the same problem with recursive enum access) is to use template specialization to do the 'if'.

Oh yeah, I'm using Visual Studio Professional 2005 SP1 with the vista/win7 fix.

+3  A: 

I suppose your compiler tries to optimize the code snippet since bob is defined const, so that the initial value of fred can be determined at compile time. Maybe you can prevent this optimization by declaring bob non-const or using the volatile keyword.

Ferdinand Beyer
you're right, the problem is that the compiler internally is doing the maths and chucking a fit when it tries to divide by zero. unfortunately the whole point of what I'm trying to do is to get the compiler to do the maths at compile time :( otherwise, what you suggest does fix the error.
matt
No - not an optimization. Integral Constant Expressions _must_ be evaluated at compile time.
MSalters
+2  A: 

Can you provide more detail on what you're trying to do with templates? Perhaps you can use a specialised template for 0 that does nothing like in the good old Factorial example and avoid the error altogether.

template <int N>
struct Blah 
{
    enum { value = 6 / N };
};

template <>
struct Blah<0> 
{
    enum { value = 0 };
};
Gary
yes, this would also fix my problem, and is what I meant when I said "use template specialization to do the 'if'" as a workaround in the question
matt
Sorry didn't notice that :) but it is the preferred way of avoiding these issues and it also lets the compiler do more work at compile time.
Gary
yeah, its also the only way I know of fixing other such errors, such as recursive calls, for instance, the following will CRASH the compiler because it always evals both sides of the 'if', fail or not: enum { value = (N>10) ? 1337 : Blah<N+1>::value };
matt
@matt: it needs to figure out what the _type_ of Blah<N+1>::value is. If that's a `long int`, then `(true) ? 1337 : Blah<N+1>::value` would be `static_cast<long int>(1337)`. So both sides must at least compile.
MSalters
+2  A: 

The problem - and the compiler has no choice in this - is that bob is a Integral Constant Expression, as is 6. Therefore 6/bob is also an ICE, and must be evaluated at compile time.

There's a very simple solution: inline int FredFromBob(int bob) { return 6/bob; } - a function call expression is never an ICE, even if the function is trivial and declared inline.

MSalters
is there any reason at all why the compiler might need to even evaluate stuff inside the 'if' when it knows at compile time that it always fails?
matt
Yes, the constant may be used as a template parameter. The compiler can't just skip the instantiation of templates, even if they would happen in a part of code that's unreachable at runtime.
MSalters