tags:

views:

260

answers:

5

Hello,

I would like to define inside a class a constant which value is the maximum possible int. Something like this:

class A
{
    ...
    static const int ERROR_VALUE = std::numeric_limits<int>::max();
    ...
}

This declaration fails to compile with the following message:

numeric.cpp:8: error: 'std::numeric_limits::max()' cannot appear in a constant-expression numeric.cpp:8: error: a function call cannot appear in a constant-expression

I understand why this doesn't work, but two things look weird to me:

  1. It seems to me a natural decision to use the value in constant expressions. Why did the language designers decide to make max() a function thus not allowing this usage?

  2. The spec claims in 18.2.1 that

    For all members declared static const in the numeric_limits template, specializations shall define these values in such a way that they are usable as integral constant expressions.

    Doesn't it mean that I should be able to use it in my scenario and doesn't it contradict the error message?

Thank you.

+7  A: 

You want:

#include <limits>

struct A {
static const int ERROR_VALUE;
}; 

const int A::ERROR_VALUE = std::numeric_limits<int>::max();

Put the class/struct in a header and the definition in a .cpp file.

anon
can ERR_VALUE defined as above be used as template argument?
aaa
What is the difference between initialization inside the class and outside? I know that I can initialize consts inside the class with integral values. Also, I must have at least one instance of such a class, right? Otherwise the compiler might decide not to initialize it?
FireAphis
Tagging along: isn't there any library here (perhaps boost) that redefine those values so that they can be used in metatemplate programming ? It would make sense to have them at our disposal at compile-time...
Matthieu M.
@aaa it can't :(
Johannes Schaub - litb
@aaa No, but that's not what he was asking about.
anon
@FireAphis No, you don't need a class instance - it's static!
anon
@Matt http://www.boost.org/doc/libs/1_40_0/boost/integer_traits.hpp integer_traits<>::const_max member does it.@Neil I was just curious
aaa
+4  A: 

Looks like a bit of a defect...

In C++0x, numeric_limits will have everything marked with constexpr, meaning you will be able to use min() and max() as compile-time constants.

UncleBens
+4  A: 

It doesn't contradict, because max is not defined static const. It's just a static member function. Functions can't be const, and static member functions can't have a const attached at the very right either.

There is also a double max() in the double version of the limits, and in C++03 it wouldn't work to say static double const max = .... So to be consistent, max() is a function for all versions of the limit template.

Now, it's known that max() not being able to be used like that is bad, and C++0x already solves it by making it a constexpr function, allowing your proposed usage.

Johannes Schaub - litb
+4  A: 

While the current standard lacks support here, for integral types Boost.IntegerTraits gives you the compile time constants const_min and const_max.

The problem arises from §9.4.2/4:

If a static data member is of const integral or const enumeration type, its declaration in the class definition can specify a constant-initializer which shall be an integral constant expression (5.19). In that case, the member can appear in integral constant expressions.

Note that it adds:

The member shall still be defined in a name- space scope if it is used in the program and the namespace scope definition shall not contain an initializer.

As others already mentioned numeric_limits min() and max() simply aren't integral constant expressions, i.e. compile time constants.

Georg Fritzsche
+1  A: 
  • I will try to answer you as much as I understood from your question:

1- If you want a static const int in your program to be initialized with a function:

int Data()
{
 return rand();
}

class A
{
public :
    static const int ee;
};
const int A::ee=Data();

This works on VS 2008

2- If you want to get max and min number for a given data type, then use these definitions INT_MAX, INT_MIN, LONG_MAX and so on..

3- If however you need to use these wrt template type, then hard code the templates yourself

template<>
int MaxData()
{
 return INT_MAX;
}

and

template<>
long MaxData()
{
 return LONG_MAX ;
}

and call them like this

int y=MaxData<int>();

4- and if you are only dealing with binary represented types only, then use this:

template <class T>
T MaxData(){
    return ~(1<<((sizeof(T)*8)-1));
}

and this

template <class T>
T MinData(){
    return (1<<((sizeof(T)*8)-1));
}

Hope this can help you..

Betamoo