• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Finalspace

C++
Problem with enum and binary or operator

52 posts in this topic

Posted (edited)

Why wont this code compile? How do i get this to compile (VC++ 2015)?

typedef enum fpl_InitFlag {
	fpl_InitFlag_None = 0,
	fpl_InitFlag_Window = 1 << 0,
	fpl_InitFlag_VideoOpenGL = 1 << 1,
} fpl_InitFlag;

static void InitSomething(fpl_InitFlag initFlags) {
	if (initFlags & fpl_InitFlag_VideoOpenGL) {
		initFlags |= fpl_InitFlag_Window;
	}
}
int main(int argc, char **args) {
	InitSomething(fpl_InitFlag_VideoOpenGL);
	return 0;
}

Error C2676    binary '|=': 'fpl_InitFlag' does not define this operator or a conversion to a type acceptable to the predefined operator

Error (active)        this operation on an enumerated type requires an applicable user-defined operator function

Edited by Finalspace
0

Share this post


Link to post
Share on other sites

Posted (edited)

Found a solution for C++ - not great that but will work:

inline fpl_InitFlag operator |(fpl_InitFlag a, fpl_InitFlag b) {
	return static_cast<fpl_InitFlag>(static_cast<int>(a) | static_cast<int>(b));
}
inline fpl_InitFlag operator &(fpl_InitFlag a, fpl_InitFlag b) {
	return static_cast<fpl_InitFlag>(static_cast<int>(a) & static_cast<int>(b));
}
inline fpl_InitFlag& operator |=(fpl_InitFlag& a, fpl_InitFlag b) {
	return a = a | b;
}

 

Edited by Finalspace
0

Share this post


Link to post
Share on other sites

I think using just enum and not enum class is the better option for bitfields, sadly. But i'm curious what comes up here... :)

0

Share this post


Link to post
Share on other sites

You can read this.

 

I personally don't like to do that just because doing arithmetic (including bitwise operations) on enums definitely lead to have values not defined in the enum. So you start with a finite set of elements and by allowing such operations you can end up with an infinite set of elements (if you limit to 'or' bitwise operations you are still stuck with a finite number of elements, but their number is large).

So typical C operations like a switch will not be able to handle easily all the values. Also, when debugging, the debugger will not be able to print the matching name of an enum value.

And if you are in C++, this tends to pervade the nature of your enumeration type.

This is just what I think about that :)

0

Share this post


Link to post
Share on other sites

Posted (edited)

51 minutes ago, Bregma said:

The compiler is just trying to save you from writing buggy code.  You need to go out of your way to force your bugs into your software.  Your solution does a fine job of doing that.

You're implementing an operator that is not closed on the enumeration set.  You're breaking the contract provided by enum.  When you start getting weird errors, save yourself some debugging time and check where you use the enum first.

A normal enum are just a single 32 bit integer value, including its field accessible by a constant.

You can even define which type your enum are. So using it as flags are totally valid, because its just a stupid integer.

And for the case the compiler may change it to maybe 64 bit integer, i dont care - because the binary operators works there as well.

 

There is no buggy code at all - its totally fine. I see no side-effects whatsoever - unless i overwrite the operators doing some weird shit.

 

Sure i could change it to enum class, but this will break C compability entirely and for a C library this is no go!

Edited by Finalspace
-1

Share this post


Link to post
Share on other sites

I've found the following pattern to be effective:

#include <stdio.h>
  
constexpr const unsigned flag[]                                                                                                                                    
= {                                                                                                                                                                
	0, 1, 2, 4, 8, 16, 32, 64, 128, 256                                                                                                                            
};                                                                                                                                                                 
                                                                                                                                                                   
struct fpl                                                                                                                                                         
{                                                                                                                                                                  
	enum init_flag                                                                                                                                                 
	{                                                                                                                                                              
		init_none,                                                                                                                                                 
		init_window,                                                                                                                                               
		init_opengl                                                                                                                                          
	};                                                                                                                                                             
                                                                                                                                                                   
	fpl( const unsigned &iflags )                                                                                                                                  
	: init_flags{ iflags }                                                                                                                                         
	{}                                                                                                                                                             
                                                                                                                                                                   
	unsigned init_flags;                                                                                                                                           
};                                                                                                                                                                 
                                                                                                                                                                   
                                                                                                                                                                   
int main( int argc, const char *args[] )                                                                                                                           
{                                                                                                                                                                  
	fpl my_fpl{ flag[ fpl::init_window ] | flag[ fpl::init_opengl ] };                                                                                       
                                                                                                                                                                   
	printf( "my_fpl flags: 0x%X\n", my_fpl.init_flags );                                                                                                           
                                                                                                                                                                   
	return 0;                                                                                                                                                      
}                                                                                                                                                                  

 

0

Share this post


Link to post
Share on other sites

I think using enumerations as flags is fine.  The whole argument that 'its bad because they're not supposed to be used that way' I think is kinda silly.  Sure you don't want to have a situation where you accidentally create an undefined bit pattern, but whether that bit pattern is an 'enum' or just an uint32_t, you still have the same error.  It'll be the same problem in the same piece of code.  The nice thing about enum's is you can have nicer names and avoid stuff like VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_NV.

Here is what I use (formatting is a bit off but you get the idea):

// --------------------------------------------------------------------------------------------------------------------------
//	enumeration expansion
//		- ENUM_CLASS_OPERATORS defines standard bit operators for enum class types
//		- ENUM_CLASS_AND_OR defines only 'and' and 'or'
// --------------------------------------------------------------------------------------------------------------------------

# define ENUM_CLASS_OPERATORS(T)																																					\
inline constexpr T operator~(T a) noexcept { return static_cast<T>(~static_cast<uint64_t>(a)); }														\
inline constexpr T operator&(T a, T b) noexcept { return static_cast<T>(static_cast<uint64_t>(a) & static_cast<uint64_t>(b)); }			\
inline constexpr T operator|(T a, T b) noexcept { return static_cast<T>(static_cast<uint64_t>(a) | static_cast<uint64_t>(b)); }			\
inline constexpr T operator^(T a, T b) noexcept { return static_cast<T>(static_cast<uint64_t>(a) ^ static_cast<uint64_t>(b)); }			\
inline T& operator&=(T& a, T b) noexcept { return a = static_cast<T>(static_cast<uint64_t>(a) & static_cast<uint64_t>(b)); }			\
inline T& operator|=(T& a, T b) noexcept { return a = static_cast<T>(static_cast<uint64_t>(a) | static_cast<uint64_t>(b)); }				\
inline T& operator^=(T& a, T b) noexcept { return a = static_cast<T>(static_cast<uint64_t>(a) ^ static_cast<uint64_t>(b)); }

# define ENUM_CLASS_AND_OR(T)																																						\
inline constexpr T operator&(T a, T b) noexcept { return static_cast<T>(static_cast<uint64_t>(a) & static_cast<uint64_t>(b)); }			\
inline constexpr T operator|(T a, T b) noexcept { return static_cast<T>(static_cast<uint64_t>(a) | static_cast<uint64_t>(b)); }			\
inline T& operator&=(T& a, T b) noexcept { return a = static_cast<T>(static_cast<uint64_t>(a) & static_cast<uint64_t>(b)); }			\
inline T& operator|=(T& a, T b) noexcept { return a = static_cast<T>(static_cast<uint64_t>(a) | static_cast<uint64_t>(b)); }	

The thing to consider is, even with bit operators, its actually quite hard to come up with a bit pattern that's undefined.  Most of code with flags looks something like:

enum class EEnumOptions {
  none,
  option_1,
  option_2,
  option_3,
  };

enum class EEnumFlags {
  none = 0,
  flag_a = 1,
  flag_b = 2,
  flag_c = 4,
  };
ENUM_CLASS_AND_OR(EEnumFlags)	// create 'and' and 'or' bit operators for EEnumName
  
// ....

void Func(EEnumOptions e, EEnumFlags f) {
  
  // handle options
  switch (e) {
    case EEnumOptions::option_1:
    case EEnumOptions::option_2:
    case EEnumOptions::option_3:
    }
  
  // handle flags
  if ((f & EEnumName::flag_a) == EEnumName::flag_a) {}		// flag_a is set
  if ((f & EEnumName::flag_b) == EEnumName::flag_b) {}		// flag_b is set
  if ((f & EEnumName::flag_c) != EEnumName::flag_c) {}		// flag_c is not set
  }

Even if you were to make a silly bit pattern, things won't 'blow up'.  Any bit pattern is still well defined.  Also if you only restrict yourself to 'and' and 'or' (ie. don't overload 'not' and 'xor'), then its near impossible to create undefined bit patterns (short of intentionally static_cast'ing them in).  Its still safer then simply integer constants or #define's, and for the most part self documenting.  I don't think anyone would have any difficulty using that function, or understanding what is expected, and passing an undefined bit pattern would have to be intentional.

Maybe its my own personal preference, but this seems clean, easy to understand, and hard to break; and isn't that what we want?

0

Share this post


Link to post
Share on other sites

This sucks really. I added another enum overload:

 

typedef enum fpl_KeyboardModifierType {
	fpl_KeyboardModifierType_None = 0,
	fpl_KeyboardModifierType_Alt = 1 << 0,
	fpl_KeyboardModifierType_Ctrl = 1 << 1,
	fpl_KeyboardModifierType_Shift = 1 << 2,
	fpl_KeyboardModifierType_Super = 1 << 3,
} fpl_KeyboardModifierType;

#ifdef __cplusplus
	inline fpl_KeyboardModifierType operator |(fpl_KeyboardModifierType a, fpl_KeyboardModifierType b) {
		return static_cast<fpl_KeyboardModifierType>(static_cast<int>(a) | static_cast<int>(b));
	}
	inline fpl_KeyboardModifierType operator &(fpl_KeyboardModifierType a, fpl_KeyboardModifierType b) {
		return static_cast<fpl_KeyboardModifierType>(static_cast<int>(a) & static_cast<int>(b));
	}
	inline fpl_KeyboardModifierType& operator |=(fpl_KeyboardModifierType& a, fpl_KeyboardModifierType b) {
		return a = a | b;
	}
#endif

and now i get this:

 

Error    C2733    'operator |': second C linkage of overloaded function not allowed

Error    C2733    'operator &': second C linkage of overloaded function not allowed

Error    C2733    'operator |=': second C linkage of overloaded function not allowed

 

I am nearly at a point, where i just want to throw of all enums and use just a struct with an uint32 value and use simple defines - so i get type checking at least for the argument type...

 

People who saying "Almost all legacy C code can be compiled with a C++ compiler" are just lying, because even this simple thing wont compile -.- I see why other C libraries dont use enums at all...

Edited by Finalspace
0

Share this post


Link to post
Share on other sites
17 hours ago, Ryan_001 said:

The whole argument that 'its bad because they're not supposed to be used that way' I think is kinda silly.

I think breaking contracts for no good reason while better alternatives exist is kinda malicious. Most, if not all bugs, originate from false assumptions. Assuming an enumeration type can only hold a single value from the enumeration has turned into a falsehood by shoehorning it into something it's not.

18 hours ago, Ryan_001 said:

Sure you don't want to have a situation where you accidentally create an undefined bit pattern

What would that be? I'd say that a randomly generated number is still well defined, a 0-bit means a flag is unset, a 1-bit means it's set. If you only have two flags, it doesn't really matter what the 3rd or 4th bits are set to. If you're talking about certain bits being mutually exclusive, your proposed solution does nothing to prevent that. It's also very common to use the bitwise not operator to disable flags, it's easy to understand and recognize.

What's this safety you are talking about? As far as I can tell you have gained nothing in preventing a programmer from making mistakes. Not only that, you've decreased legibility and increased the mental load to deal with silly mistakes. Mistakes that should barely take any time at all to fix in the first place, for some misguided sense of safety.

0

Share this post


Link to post
Share on other sites
18 hours ago, Ryan_001 said:

Sure you don't want to have a situation where you accidentally create an undefined bit pattern, but whether that bit pattern is an 'enum' or just an uint32_t, you still have the same error.

The difference is that an enum is explicitly designed to stop you getting into the situation where you're using unexpected values, by asking you to specify which value you want by name. Deliberately thwarting that system means you lose some of the benefits. (You keep some benefits, such as a degree of type safety, so I can see why it's frustrating to have an all-or-nothing decision here.)

Going back to the original post and the most recent problem:

6 minutes ago, Finalspace said:

Error    C2733    'operator |': second C linkage of overloaded function not allowed

Looks like the function is not inlined. I've no idea why that might be the case, but maybe there are some settings or macros that switch it off.

1

Share this post


Link to post
Share on other sites
44 minutes ago, Kylotan said:

The difference is that an enum is explicitly designed to stop you getting into the situation where you're using unexpected values, by asking you to specify which value you want by name. Deliberately thwarting that system means you lose some of the benefits. (You keep some benefits, such as a degree of type safety, so I can see why it's frustrating to have an all-or-nothing decision here.)

Going back to the original post and the most recent problem:

Looks like the function is not inlined. I've no idea why that might be the case, but maybe there are some settings or macros that switch it off.

For me enums are just a group of named integers, so i can access it in C++ by Enum::A and in C Enum_A.

How i use them, is up to me - maybe i just want flags, maybe i want single states? I dont care.

 

If i want extra hard type safety, i just use enum class - but most of the time i just want grouped flags, so i dont accidently set a keyboard_flag on a init_flag... Thats all i want for safety.

Is that so hard for c++? Other languages like c# and even old pascal can do this right.

 

Hmm i know that inline is just a "hint" to the compiler, but this is totally wrong... maybe i need some template magic to get it to compile and behave.

Edited by Finalspace
0

Share this post


Link to post
Share on other sites
5 minutes ago, Finalspace said:

For me enums are just a group of named integers [...]

How i use them, is up to me - maybe i just want flags

But the key point there, is that your combination of 2 enum values boolean-ored together is no longer in your "group of named integers". It's related to them, sure, but it's outside the group. It was never named, after all.

Imagine this:

const int ONE = 1;
const int TWO = 2;

And now say you want to be able to perform division on 2 of these values, which returns 0.5. But 0.5 isn't in the 'int' set, so you probably shouldn't expect to be able to pretend that it is the same type, just like the value corresponding to 3 isn't in fpl_InitFlag. C and C++ let you get away with it for enums because of an implementation detail that they're stuck supporting forever.

Arguably there should be a different concept entirely for boolean flags like this, but we don't have that in C++.

 

11 minutes ago, Finalspace said:

Is that so hard for c++?

It's not, and it works in C++, and many people have been exploiting this equivalence to integers for a long time. You're almost certainly just doing something wrong at your end.

2

Share this post


Link to post
Share on other sites

This is very strange. Can someone point me to the part of the standard that says that a variable with an enum type can only hold values that are named constants? I have looked, and I haven't found it. Also, using powers of 2 as constants so you can do bit arithmetic is so common in C that I very much doubt C++ disallows it.

 

EDIT: I found this paragraph in section 7.2:

"For an enumeration whose underlying type is fixed, the values of the enumeration are the values of the underlying type. Otherwise, for an enumeration where e min is the smallest enumerator and e max is the largest, the values of the enumeration are the values in the range b min to b max , defined as follows: Let K be 1 for a two’s complement representation and 0 for a one’s complement or sign-magnitude representation. b max is the smallest value greater than or equal to max(|e min | − K, |e max |) and equal to 2 M − 1, where M is a non-negative integer. b min is zero if e min is non-negative and −(b max + K) otherwise. The size of the smallest bit-field large enough to hold all the values of the enumeration type is max(M, 1) if b min is zero and M + 1 otherwise. It is possible to define an enumeration that has values not defined by any of its enumerators. If the enumerator-list is empty, the values of the enumeration are as if the enumeration had a single enumerator with value 0."

 

In Hodgman's example, b min is 0 and b max is 7. So cases 0, 5, 6 and 7 are kosher.

 

 

Edited by alvaro
Found relevant information
0

Share this post


Link to post
Share on other sites

I'm not trying to be a jerk here, but I don't see the standard supporting many of your claims on enumerations.  The relevant parts are in n4659 section 10.2 (also refer to section 8.2.9 (9) and (10)).

There is no contractual obligation to only store an enumerated value in an enumeration (10.2 (8) "For an enumeration whose underlying type is fixed, the values of the enumeration are the values of the underlying type").  You can store any value in an enum even if it is not explicitly enumerated provided the underlying type supports the value.  It even says in 10.2 (1) "An enumeration is a distinct type (6.9.2) with named constants.".  Its no different than a bunch of static const int's except that it obeys the type system.  The size of the underlying type is either explicitly specified, or determined according to 10.2 (5) (7) and (8).  As long as you stay within the range of the underlying type, your program will not be undefined.  The underlying bit pattern does not need a corresponding enumerated constant.

The compiler does not 'optimize' an enumeration any differently than any other type.  A switch on an enumeration, is the same as a switch on the underlying type.  It can't treat enum's as special constructs because static_cast is allowed (see 8.2.9 (9) and (10)).

You can static_cast a value back to an enumeration (8.2.9 (10)) provided that "the original value is within the range of the enumeration values"; and as per 10.2 (8) "the values of the enumeration are the values of the underlying type".

It is clear from the standard that enumerations are allowed to be treated as flags, that the underlying type must be (and is) well defined.  That storing bit patterns/values that do not have corresponding enumerations is well defined, and that operating on values using bit operations is well defined.

If you personally (or within your company) wish to use enum as a list of mutually exclusive options, then so be it.  But enum's are used for all sorts of integer constants (flags, options, counters, and half dozen other things), and are well defined in the spec to be capable of doing so.

1

Share this post


Link to post
Share on other sites

Well at this point i have given up. Now i will use enums for single states only and use this for my flags - compiles in C and C++ (For C i require prefixing anyway...):

	typedef struct fpl_KeyboardModifierType {
		uint32_t value;
	} fpl_KeyboardModifierType;

	const uint32_t fpl_KeyboardModifierType_Alt = 1 << 0;
	const uint32_t fpl_KeyboardModifierType_Ctrl = 1 << 1;
	const uint32_t fpl_KeyboardModifierType_Shift = 1 << 2;
	const uint32_t fpl_KeyboardModifierType_Super = 1 << 3;

	inline fpl_KeyboardModifierType CreateKeyboardModifierType(uint32_t value) {
		fpl_KeyboardModifierType result;
		result.value = value;
		return(result);
	}

	static void doSomethingWithKeyboardModifiers(fpl_KeyboardModifierType modifiers) {
		if (modifiers.value & fpl_KeyboardModifierType_Ctrl) {
			// ...
  		}
	}

 

Sure i lost type safety that way, but its better than nothing...

Edited by Finalspace
0

Share this post


Link to post
Share on other sites

Are you trying to find a way to write new enums that will compile as both C and C++ or are you modifying existing C code to compile with a C++ compiler?

The following method works for both and has type-checking in C++. Perhaps it will require less modifications to existing C code than adding operators to C++ code?:

#include <stdio.h>


typedef enum
{
	flag0,
	flag1,
	flag2,
	flag3 = 4,
	flag4 = 8
} test_flags;

void config( test_flags iflags[4] )
{
	unsigned uflags[] = { iflags[0], iflags[1], iflags[2], iflags[3] };

	printf( "0x%X\n", uflags[0] | uflags[1] | uflags[2] | uflags[3] );
}

int main( int argc, const char *args[] )
{
	test_flags my_flags[] = { flag1, flag2, flag3, flag4 };
	unsigned badflags[] = { 30, 40, 50, 32 };

	config( badflags ); // not accepted by C++
	config( my_flags );

	return 0;
}

 

1

Share this post


Link to post
Share on other sites

Finalstate, look at my first post, you can use that.  I showed you how to do it.

Also your attempt where you claimed you had compilation errors, works fine on my end, here's the full code:

# include <thread>
# include <mutex>
# include <condition_variable>
# include <vector>
# include <deque>
# include <atomic>
# include <iostream>
# include <functional>
# include <algorithm>

using namespace std;




typedef enum fpl_KeyboardModifierType {
	fpl_KeyboardModifierType_None = 0,
	fpl_KeyboardModifierType_Alt = 1 << 0,
	fpl_KeyboardModifierType_Ctrl = 1 << 1,
	fpl_KeyboardModifierType_Shift = 1 << 2,
	fpl_KeyboardModifierType_Super = 1 << 3,
} fpl_KeyboardModifierType;

#ifdef __cplusplus
	inline fpl_KeyboardModifierType operator |(fpl_KeyboardModifierType a, fpl_KeyboardModifierType b) {
		return static_cast<fpl_KeyboardModifierType>(static_cast<int>(a) | static_cast<int>(b));
	}
	inline fpl_KeyboardModifierType operator &(fpl_KeyboardModifierType a, fpl_KeyboardModifierType b) {
		return static_cast<fpl_KeyboardModifierType>(static_cast<int>(a) & static_cast<int>(b));
	}
	inline fpl_KeyboardModifierType& operator |=(fpl_KeyboardModifierType& a, fpl_KeyboardModifierType b) {
		return a = a | b;
	}
#endif


void Func(fpl_KeyboardModifierType f) {
	if (f & fpl_KeyboardModifierType_Alt) cout << "fpl_KeyboardModifierType_Alt" << endl;
	if (f & fpl_KeyboardModifierType_Ctrl) cout << "fpl_KeyboardModifierType_Ctrl" << endl;
	if (f & fpl_KeyboardModifierType_Shift) cout << "fpl_KeyboardModifierType_Shift" << endl;
	if (f & fpl_KeyboardModifierType_Super) cout << "fpl_KeyboardModifierType_Super" << endl;
	}


// ----- main -----
void main() {

	Func(fpl_KeyboardModifierType_Shift | fpl_KeyboardModifierType_Super);


	// done
	std::cout << "done" << std::endl;
	getchar();
	}

Just copied/paste and threw it together, no changes needed.  What you were doing worked fine.  Its best to test these things in a smaller 'test unit' alone, and then bring them into the larger project.

0

Share this post


Link to post
Share on other sites
1 hour ago, Ryan_001 said:

Finalstate, look at my first post, you can use that.  I showed you how to do it.

Also your attempt where you claimed you had compilation errors, works fine on my end, here's the full code:


# include <thread>
# include <mutex>
# include <condition_variable>
# include <vector>
# include <deque>
# include <atomic>
# include <iostream>
# include <functional>
# include <algorithm>

using namespace std;




typedef enum fpl_KeyboardModifierType {
	fpl_KeyboardModifierType_None = 0,
	fpl_KeyboardModifierType_Alt = 1 << 0,
	fpl_KeyboardModifierType_Ctrl = 1 << 1,
	fpl_KeyboardModifierType_Shift = 1 << 2,
	fpl_KeyboardModifierType_Super = 1 << 3,
} fpl_KeyboardModifierType;

#ifdef __cplusplus
	inline fpl_KeyboardModifierType operator |(fpl_KeyboardModifierType a, fpl_KeyboardModifierType b) {
		return static_cast<fpl_KeyboardModifierType>(static_cast<int>(a) | static_cast<int>(b));
	}
	inline fpl_KeyboardModifierType operator &(fpl_KeyboardModifierType a, fpl_KeyboardModifierType b) {
		return static_cast<fpl_KeyboardModifierType>(static_cast<int>(a) & static_cast<int>(b));
	}
	inline fpl_KeyboardModifierType& operator |=(fpl_KeyboardModifierType& a, fpl_KeyboardModifierType b) {
		return a = a | b;
	}
#endif


void Func(fpl_KeyboardModifierType f) {
	if (f & fpl_KeyboardModifierType_Alt) cout << "fpl_KeyboardModifierType_Alt" << endl;
	if (f & fpl_KeyboardModifierType_Ctrl) cout << "fpl_KeyboardModifierType_Ctrl" << endl;
	if (f & fpl_KeyboardModifierType_Shift) cout << "fpl_KeyboardModifierType_Shift" << endl;
	if (f & fpl_KeyboardModifierType_Super) cout << "fpl_KeyboardModifierType_Super" << endl;
	}


// ----- main -----
void main() {

	Func(fpl_KeyboardModifierType_Shift | fpl_KeyboardModifierType_Super);


	// done
	std::cout << "done" << std::endl;
	getchar();
	}

Just copied/paste and threw it together, no changes needed.  What you were doing worked fine.  Its best to test these things in a smaller 'test unit' alone, and then bring them into the larger project.

 

finalstate *sigh*

 

A single enum will compile, but a second one will break it!

 

I tested it on vs 2015 and 2017:

Adding a second enum compiles... will test it out in my library...

Edited by Finalspace
Wrong statement
0

Share this post


Link to post
Share on other sites

You don't need the "typedef" in C++.

 

Hm, and while nit-picking, "main" returns an integer.

Edited by Alberth
more suggestions to change
0

Share this post


Link to post
Share on other sites
On 7/14/2017 at 8:34 AM, Finalspace said:

A normal enum are just a single 32 bit integer value, including its field accessible by a constant.

Nope.  It is implementation dependent size if none is specified, and on most major compilers defaults to a 32 bit signed integer usually, but sometimes defaults to a 32 bit unsigned value or a 64 bit signed or unsigned value, and may potentially be something else entirely.

On 7/14/2017 at 8:34 AM, Finalspace said:

So using it as flags are totally valid, because its just a stupid integer.

No. An enum is not "just a stupid integer".  At no point in the language history has it ever been "just a stupid integer". Even going back to C, an enum was something more specific than the two things it replaced, a stupid integer constant and a macro-defined value. An enum is more than either of those things.  By calling it an enum you are assigning it specific meaning which the compiler can use.  You are -- as a convenience -- treating it as an integer.  

You are also treating it as a plain int, which, by the way, is also mostly going away.  If you have a plain old int in modern code then you're doing something wrong.  Specify the width and signed-ness.

10 minutes ago, Finalspace said:

I have no idea why it wont compile, i made a branch and checked in the enum operators - last try before i give up:

You have been told why, and provided with THREE alternate solutions to do what you are trying to do.

The language is trying to protect you.  If you are dead-set on removing those protections you are free to do so, but it is not a wise decision.

Telling the compiler you have one intention, then moving on with a different set of uses that violate those intentions, that is a sure-fire way to introduce bugs in your program.

1

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now

  • Similar Content

    • By Khairul90
       
      Hey guys I'm a newbie here and interested in game development. A little background, I went to college for a while and learnt C++ and Java, however due to personal reasons at that time I was not able to get most out of my classes. You can say that I'm a little proficient in C++ like I know how to use loops, functions and abit of pointers. I'd like to do game development in my free time and build my portfolio at the same time. So how do I go about this?
      I understand that there are many things in game dev such as cameras, math, AI and the engine. I do not know where to start. should I go back and brush up on my C++ or can I dive into something that is less intensive and learn and build from there? I'm currently reading the book by Jason Gregory of Naughty Dog, Game engine architecture. I'm pretty sure most of the technical stuff would fly over my head but the concepts are very interesting. One of my goals would be to build an engine in the far future.
      Can you guys fill me in on what to do and how to approach this?
       
      Khairul 
    • By Inline Engine
      Hello Everybody,

      Our professional experienced hobby team (5 active members) is looking for Volunteers to take a seat in the development of a next generation C++ 3D Game Engine.

      The minimum requirement is 2 years personal experience in C++ or game/engine related programming.

      The Engine:

      - Cross Platform & Clean Code Design ( For now we only want to aim PC & Console )

      - Fully Customizable Graph Based DirectX12 Graphics Engine, (PBR is in progress)

      - Own Editor + UI system + Math library

      - (Will be) multithreaded with Job Based System like in Uncharted 4's engine

      Roles we are looking for now: (Later will be more)
      - Editor & UI & Tools Programmer

      - Generalist Programmer

      Picture from the current early state of the editor:
      https://pasteboard.co/eb4hfgGM3.png

      Source code: https://github.com/petiaccja/Inline-Engine

      If you have the passion to build game engines / games write an e - mail to: InlineEngine@gmail.com
    • By Solid_Spy
      Hello, I have been working on SH Irradiance map rendering, and I have been using a GLSL pixel shader to render SH irradiance to 2D irradiance maps for my static objects. I already have it working with 9 3D textures so far for the first 9 SH functions.
      In my GLSL shader, I have to send in 9 SH Coefficient 3D Texures that use RGBA8 as a pixel format. RGB being used for the coefficients for red, green, and blue, and the A for checking if the voxel is in use (for the 3D texture solidification shader to prevent bleeding).
      My problem is, I want to knock this number of textures down to something like 4 or 5. Getting even lower would be a godsend. This is because I eventually plan on adding more SH Coefficient 3D Textures for other parts of the game map (such as inside rooms, as opposed to the outside), to circumvent irradiance probe bleeding between rooms separated by walls. I don't want to reach the 32 texture limit too soon. Also, I figure that it would be a LOT faster.
      Is there a way I could, say, store 2 sets of SH Coefficients for 2 SH functions inside a texture with RGBA16 pixels? If so, how would I extract them from inside GLSL? Let me know if you have any suggestions ^^.
    • By MarcusAseth
      I am watching at this page -> https://msdn.microsoft.com/en-us/library/windows/desktop/dd371301(v=vs.85).aspx
      HRESULT CreateStrokeStyle( [ref] const D2D1_STROKE_STYLE_PROPERTIES &strokeStyleProperties, [in, optional] const FLOAT *dashes, UINT dashesCount, [out] ID2D1StrokeStyle **strokeStyle ); notice the second optional argument followed by two non-optional ones...how in the world am I supposed to use the function without passing the second argument, if it is on the middle?! x_x
    • By MarcusAseth
      I have this Direct2D framework set up, it render a constant 60FPS and this is my code in my draw call:
      mRenderTarger->Clear(D2D1::ColorF(0.41f, 0.41f, 0.41f, 1.0f)); GetCursorPos(&mMouse); ScreenToClient(mhWindow, &mMouse); D2D1_POINT_2F point2 = D2D1::Point2F(mMouse.x, mMouse.y); //wrapper function of the Direct2D FillEllipse function drawPoint(point2, 6.f, D2D1::ColorF(1.0f, 0.15f, 0.30f, 1.f)); Now even without moving the mouse too fase, the point drawn kind of lag behind a bit, and moving the mouse faster, the point is drawn as far as 5cm from my mouse cursor so the lag is visible.
      Any idea why this accurs and how to fix it? 
  • Popular Now