Assigning an enum a max value via numeric_limits? - c++

I'm having trouble assigning an element in an enuma max value. First:
protected:
enum {DEFAULT_PADDING=std::numeric_limits<enum>::max()};
Results in:
./basecode.h:30:51: error: expected identifier or '{'
enum {DEFAULT_PADDING=std::numeric_limits<enum>::max()};
^
./basecode.h:30:59: error: expected a type
enum {DEFAULT_PADDING=std::numeric_limits<enum>::max()};
(and a couple of others)
Second, switching to:
protected:
enum {DEFAULT_PADDING=std::numeric_limits<unsigned int>::max()};
Results in:
./basecode.h:30:27: error: expression is not an integral constant expression
enum {DEFAULT_PADDING=std::numeric_limits<unsigned int>::max()};
How do I have numeric_limits give me a value that I can use at compile time for an enum?
The library is older, so it supports a lot of older compilers and IDEs. I need something that is at least C++03 and preferably C++98.
And standard caveats apply: this is a simple make based project. It does not use Autotools, it does not use Cmake, it does not use Boost, etc.

In C++03, std::numeric_limits<T>::max() was simply static. In C++11, it became static constexpr. You need the latter in order to be used in an integral constant expression, so simply compiling with -std=c++11 will do.
If you can't use C++11, you can just use UINT_MAX.

Related

Boost doesn't seem to enable constexpr for std::numeric_limits with multiprecision types

I want to do some compile-time evaluation using boost multiprecision numbers.
Therefore I wrote some code, which does't compile properly.
I traced down the problem to this:
typedef boost::multiprecision::cpp_bin_float_oct test_t;
constexpr test_t nEps = std::numeric_limits<test_t>::epsilon();
which resulted in several error messages under MSVC 2017:
error C2127: 'nEps': illegal initialization of 'constexpr' entity with a non-constant expression
...\boost_1_75_0\boost\multiprecision\cpp_bin_float.hpp(1842): note: failure was because type 'test_t' is not a literal type
...\boost_1_75_0\boost\multiprecision\number.hpp(1982): note: type 'boost::multiprecision::number<boost::multiprecision::backends::cpp_bin_float<237,boost::multiprecision::backends::digit_base_2,void,int32_t,-262142,262143>,boost::multiprecision::et_off>' is not a literal type because its data member 'm_backend' is of non-literal type 'boost::multiprecision::backends::cpp_bin_float<237,boost::multiprecision::backends::digit_base_2,void,int32_t,-262142,262143>'
...\boost_1_75_0\boost\multiprecision\cpp_bin_float.hpp(1842): note: type 'boost::multiprecision::backends::cpp_bin_float<237,boost::multiprecision::backends::digit_base_2,void,int32_t,-262142,262143>' is not a literal type because it is not an aggregate type, a closure type, or does not have a constexpr constructor that is not a copy or move constructor
If I use const instead of constexpr, then the compiler works, but of course doesn't do compile-time evaluation, which is my target.
How can I overcome the issue? Maybe I have to use specific compiler settings or maybe boost isn't able to do compile-time evaluation with multiprecision types (I used boost v1.75.0)?

Initialising constexpr - " illegal initialization of 'constexpr' entity with a non-constant expression"

I have two enum class types: Type and SocketType. The following code won't compile and fails with the message mentioned in the question, in VC++ 2017:
static constexpr std::map<Type,SocketType> PacketTypeMap =
{
{Type::JUSTJOINED, SocketType::TCP},
{Type::CHAT_MESSAGE, SocketType::TCP},
{Type::REQUEST_WORLD, SocketType::TCP},
{Type::DATA_WORLD, SocketType::TCP},
{Type::DATA_PLAYER, SocketType::UDP},
{Type::RESPAWN_PLAYER, SocketType::TCP}
};
Been trying some variations and nothing works, but I'm sure I'm just missing something simple with the syntax.
std::map is not compatible with constexpr. There exists an experimental(?) library called frozen, which provides a constexpr-compatible frozen::map (besides frozen::unordered_map, frozen::string, and others).
However, most probably you just want to pick a simpler solution (e.g., a switch statement in a constexpr function).
Migrating the answer from the comments section into the answer section.
There are no constexpr maps. It uses dynamic allocation, which is not possible with constexpr. Get rid of constexpr, or use a different container for compile-type map.

'=' should initialize either all enum members or only the first;

I am trying to build my code with following enum values :
typedef enum {
YUV_420P=0,
YUV_422P,
RGB_P,
BAYER_P,
YUV_422IBE,
YUV_444IBE,
A_1BIT,
YUV_420SP,
COMPLEX_8BIT,
COMPLEX_16BIT,
COMPLEX_32BIT,
COMPLEX_U8BIT,
COMPLEX_U16BIT,
COMPLEX_U32BIT,
ALPHA_TYPE=0x8000
} Format;
But during building I am getting the below linting warning ..
sample.h: Note 960: Violates MISRA 2004 Required Rule 9.3, '=' should initialize either all enum members or only the first; enumerator: 'ALPHA_TYPE' ..
I don't want to change value of ALPHA_TYPE and I want to put the ALPHA_TYPE in this enum only. How can I resolve this?
Your code already does what you want. You just need to suppress this particular warning.
On the other hand, if you absolutely do need to adhere to this MISRA 2004 rule 9.3, then you will need to change your code and find a different solution. But you cannot have it both ways.
If values of other enums does not matter, you can do this
typedef enum {
ALPHA_TYPE=0x8000,
YUV_420P,
YUV_422P,
RGB_P,
BAYER_P,
YUV_422IBE,
YUV_444IBE,
1BIT,
YUV_420SP,
COMPLEX_8BIT,
COMPLEX_16BIT,
COMPLEX_32BIT,
COMPLEX_U8BIT,
COMPLEX_U16BIT,
COMPLEX_U32BIT
} Format;
Or
Define all your enum values like this (this avoid one of your enum value to change, if you add a new one)
typedef enum {
YUV_420P=0,
YUV_422P=1,
RGB_P=2,
BAYER_P=3,
YUV_422IBE=4,
YUV_444IBE=5,
1BIT=6,
YUV_420SP=7,
COMPLEX_8BIT=8,
COMPLEX_16BIT=9,
COMPLEX_32BIT=10,
COMPLEX_U8BIT=11,
COMPLEX_U16BIT=12,
COMPLEX_U32BIT=13,
ALPHA_TYPE=0x8000
} Format;
This is certainly not a C++ requirement.
[C++11: 7.2/2]: An enumerator-definition with = gives the associated enumerator the value indicated by the constant-expression. If the first enumerator has no initializer, the value of the corresponding constant is zero. An enumerator-definition without an initializer gives the enumerator the value obtained by increasing the value of the previous enumerator
by one.
The grammar above it allows multiple enumerators to have an initializer.
If you are allowed, perhaps you can turn off checks for compliance with this "MISRA 2004" rule. You could also simply ignore it since it appears to be a mere Note. Personally I would be a bit annoyed to have that popping up all the time, but perhaps that's just me.
Since the first enum value is 0, and since it is that also by default, simply use the default. ← I misread the warning, this point is not a solution.
And/or, turn off the MISRA rule checking.
And/or, ignore the specific note. Apparently you can do that via an +esym option. Or maybe -esym, just try out things and check the documentation.

Enum declaration in Eclipse

I'm compiling a c++ project in Eclipse, Linux.
The project was compiled in Windows in the past.
I have my declaration of enums like this:
enum nameofenum:UINT32
{
one=0,
two=1
}
The result is an error in eclipse.
What is the meaning of :UINT32?
How can I switch this declaration to Linux?
Thanks!!
That looks like a strongly typed enum, which is a C++0x feature. Basically, it specifies the underlying type of the enumeration, so one and two will be UINT32s.
To compile it, you need a compiler that supports this particular part of the C++0x language. I believe GCC 4.4 and Visual C++ supports strongly typed enums to some extent.
The : UINT32 declares the underlying type of the enumeration; it means that the enumeration will be represented by a UINT32.
This is a new C++ feature that is being added in C++0x called strongly typed enumerations. Visual C++ has supported it at least since Visual C++ 2005; the version of g++ you are using may not support it.
As for how you get this working with g++, it depends. If you don't have any code that relies on a particular underlying type, then you can just remove it. If you do have code that relies on a particular underlying type, you might consider replacing uses of the enumeration type with the underlying type (i.e., use UINT32 instead of nameofenum); this isn't very nice, though.
UINT32 is unsigned 32bit integer, so your enum is representated by 4bytes int.
It depends. I dont' know exactly, but do you really need to use this enum as 32bit int? May be you just can avoid this :UINT32 declaration?
: UINT means that the underlying type of the enumeration identifiers is UINT.
It is a Microsoft extension described here. To make it compile remove : UINT.

Do all C++ compilers allow using a static const int class member variable as an array bound?

In VC++ when I need to specify an array bound for a class member variable I do it this way:
class Class {
private:
static const int numberOfColors = 16;
COLORREF colors[numberOfColors];
};
(please don't tell me about using std::vector here)
This way I have a constant that can be used as an array bound and later in the class code to specify loop-statement constraints and at the same time it is not visible anywhere else.
The question is whether this usage of static const int member variables only allowed by VC++ or is it typically allowed by other widespread compilers?
This is valid C++ and most (all?) reasonably modern compilers support it. If you are using boost, you can get portable support for this feature in the form of BOOST_STATIC_CONSTANT macro:
class Class {
private:
BOOST_STATIC_CONSTANT(int, numberOfColors = 16);
COLORREF colors[numberOfColors];
};
The macro is expanded to static const int numberOfColors = 16 if the compiler supports this, otherwise it resorts to enum { numberOfColors=16 };.
That behavior is valid according to the C++ Standard. Any recent compiler should support it.
I believe that Visual Studio 2005 and beyond supports it. The XCode C++ compiler as well (this is gcc actually).
If you want to be safe you could always use the old enum hack that I learned from Effective C++. It goes like this:
class Class {
private:
enum {
numberOfColors = 16
};
COLORREF colors[numberOfColors];
};
Hope this helps.
This has been standard C++ for more than a decade now. It's even supported by VC -- what more could you want? (#Neil: What about SunCC? :^>)
Yes, it's 100% legal and should be portable. The C++ standard says this in 5.19 - Constant expressions" (emphasis mine):
In several places, C++ requires expressions that evaluate to an integral or enumeration constant: as array bounds (8.3.4, 5.3.4), as case-expressions (6.4.2), as bit-field lengths (9.6), as enumerator initializers (7.2), as static member initializers (9.4.2), and as integral or enumeration non-type template arguments (14.3).
constant-expression:
conditional-expression
An integral constant-expression can involve only literals (2.13), enumerators, const variables or static data members of integral or enumeration types initialized with constant expressions (8.5), non-type template parameters of integral or enumeration types, and sizeof expressions.
That said, it appears that VC6 doesn't support it. See StackedCrooked's answer for a good workaround. In fact, I generally prefer the enum method StackedCrooked mentions for this type of thing.
As an FYI, the "static const" technique works in VC9, GCC 3.4.5 (MinGW), Comeau and Digital Mars.
And don't forget that if you use a "`static const'" member, you'll need a definition for it in addition to the declaration strictly speaking. However, virtually all compilers will let you get away with skipping the definition in this case.
Besides other answers you can use following function do determine number of elements in statically alocated arrays:
template<typename T, size_t length>
size_t arrayLength(T (&a)[length])
{
return length;
}
I'm pretty sure that this will also work with gcc and Solaris, but I can't verify this at the moment.
In the future you could extend the idea like this:
template<int size>
class Class {
private:
COLORREF colors[size];
};
and use it like this:
Class<5> c;
so that you are not limited to exactly one buffer size in your application.
I've stopped bothering about the portability of that years ago. There are perhaps still compilers which don't support it, but I haven't met any of them recently.
It is possible to answer questions like this by referencing the ISO C++ speicifcation but the spec is hard for people to get and harder to read.
I think the simplest answer hinges on two things:
Microsoft Visual Studio 2005 and up is a relatively conformant C++ implementation. If it allows you to do something, chances are its standard.
Download something like Code::Blocks to get a GCC compiler to try stuff out. If it works in MS and GCC, chances really are, its standard.