how to use boolean expression in switch in C++ - c++

I need to convert the if else into switch statement, please help:
if (XMLString::compareString(xmlch_Title, XMLString::transcode("abc")) == 0 ) {
out_Config.abc = XMLString::transcode(xmlch_Value);
} else if (XMLString::compareString(xmlch_Title, XMLString::transcode("def")) == 0 ) {
out_Config.def = XMLString::transcode(xmlch_Value);
} .......

Note: Using a boolean expression as the condition of a switch would, in your case, be of little use since you then could only have two possible outcomes of the switch-statement:
Going to "case true: ", or "case false: "
Introduction
As stated in the Standard (n3797), the condition used with a switch must be implicitly convertiable to either integral, or enumeration, type.
6.4.2p2 The switch statement [stmt.switch]
The condition shall be of integral type, enumeration type, or class type. If of class type, the condition is contextually implicitly converted (Clause 4) to an integral or enumeration type**. Integral promotions are performed. Any statement within the switch statement can be labeled with one or more case labels as follows:
case constant-expression:
where the constant-expression shall be a converted constant expression (5.19) of the promoted type of the switch condition. No two of the case constans in the same switch shall have the same value after conversion to the promoted type of the switch condition.
What this means is that the theoretical implementation below is ill-formed, since std::string can't implicitly be converted to an integral or enumeration type (1), and neither is it usable in a constant-expression (2).
std::string get_string ();
switch (get_string ()) { // (1)
case std::string ("stack"): ...; // <----.
case std::string ( "over"): ...; // <----|-- (2)
case std::string ( "flow"): ...; // <----'
}
Am I completely out of luck?
Not really, if you were to use a hashing function to generate a hash for the strings involved, you can theoretically use a switch; just be careful about potential collisions of said hashes.
Also note that there must be an implementation usable in constant-expressions for the case-labels.
Is it worth writing such complex code to solve this kind of problem? Probably not.

if you want to factor out the common part, you'll probably need to use an array of struct containing the transcoded string constant and a lambda doing the then operation. Something along the lines of:
#include <functional>
struct check_case {
const XMLString code;
const std::function <void (Config &, const XMLString &)> handler;
};
check_case check_list[2] = {
{XMLString::transcode("abc"), [](Config &out_Config, const XMLString &code) { out_Config.abc = code;}},
{XMLString::transcode("def"), [](Config &out_Config, const XMLString &code) { out_Config.def = code;}},
};
for (auto c : check_list) {
if (XMLString::compareString(xmlch_Title,c.code) == 0){
c.handler(out_Config, XMLString::transcode(xmlch_Value));
break;
}
}
It's still quite verbose though, and I'm not sure you'd find it more easily readable. Besides, you don't get to cascade your handlers as you could with a normal switch (which was perhaps the original reason for your question).
Alternatively, you could embed all that in a dedicated class, where it's easier to build a context (the class instance member fields). There it would be easier to cascade methods manually. As above, the readability isn't quite up to par either.

Look at it from a different point of view. Do it in two stages...
Stage 1: Extract the text in the quotes "abc" or "def"
Stage 2: switch (based on variable from stage 1) and case will provide implementation

Related

Switch statements with Classes

We are currently studying classes in my Computing Science class. Today, the teacher introduced us to Switch Statements and I had the following question which he wasn't sure of:
Can switch statements be used alongside classes if we overload the == operator?
Exactly as you phrased the question: No. But it is possible to design a class that is compatible witch switch. This is an example using a barebones wrapper class for integers:
// Only possible in C++11 and newer.
class Integer
{
public:
constexpr explicit Integer(int p) : m_payload(p) {} // (1)
constexpr operator int() const { return m_payload; } // (2)
private:
int m_payload;
};
int main()
{
// For simplicity. This could be a user input or some other value
// determined when running the program.
Integer five(5);
switch (five) { // (4)
case Integer(5): // (3)
return 0;
default:
return 1;
}
}
I’m going to gloss over a lot of finer details. What the code does is this:
The value evaluated by the switch – in this case five in line (4) – must be either an integer-like value or implicitly convertible to an integer-like value. That’s what the operator int() (2) does – it’s called a conversion operator.
The cases of a switch must be constant integral expressions, i.e. they must must evaluate to an integer-like value and the evaluation must be possible at compile-time. To make line (3) work all of the following must be true:
An Integer object must be able to be created at compile-time. That is provided by the constexpr constructor in line (1). The constexpr is key here.
The object must be created with a value that’s actually known at compile time. That’s the literal 5 in line (3). You could not run your program, query the user for an integer and use that user input instead of the 5. The compiler has no way to anticipate the user’s input, after all.
An Integer object must be implicitly convertible to an integer-like value at compile time. That’s provided by the constexpr in like (2).
To sum up: Yes, you can design your own classes to be compatible with switch. But rather severe restrictions apply, and it has nothing to do with operator==().

Automatic conversion of intrinsic types to enum in C++

Problem sounds painfully familiar.
Assume you have enum:
enum MyEnum {first, second, third};
Now I want convert some int to MyEnum. Naive approach
int i = 2;
MyEnum e = (MyEnum)i;
Seems OK, but it is not. First, 2 will be converted to 'third' and not to 'second' as one would expect. Second, this conversion is dumb and I would like a smart one.
Motivation is as follows:
void foo(MyEnum e) { ... }
...
foo(2);
And that foo() should always receive 'second' for 2 no matter what is actual value of this enum.
There are 2 obvious solutions:
Write conversion function and always invoke it
Overload casting operator
1st solution is obviously terrible. Don't want write foo(convetIntToMyEnum(2));
I want write foo(2) and compiler will automatically invoke my conversion function. So 2nd solution is what I need. If 'int' was my own class, then overloading of cast operator is trivial. But 'int' is intrinsic type.
I vaguely remember there is possibility for that, but can't find it. Appreciate cure for my blond moment.
You cannot overload the "casting operator" (normally this is either a "converting constructor" or a "user defined conversion operator") for an enum, since it's not a class and thus cannot have member functions or constructors.
You'd likely want something like this:
class my_enum
{
public:
enum MyEnum {first=0x1000, second=0x2000, third=...};
private:
MyEnum m_value;
public:
my_enum(int _value) {
switch (_value) {
case 1: m_value = first; break;
case 2: m_value = second; break;
case 3: m_value = third; break;
default: throw std::invalid_argument("invalid value");
}
}
operator int() const {
switch (m_value) {
case first: return 1;
case second: return 2;
case third: return 3;
default: return 0;
}
}
};
void foo(my_enum e)
{
...
}
You can define whatever mapping from int to enum value that you want, as long as it's invertible. Because the constructor and cast operator are not explicit, this will allow the implicit conversions you want.
There is the third and obvious solution: don't use an integer as argument to your function, and instead directly use your enum. Just make it an enum class while you're at it! Added bonus: increased code clarity. This is really no reason to start writing all kinds of unexpected conversions for a bad function prototype.
If these functions are given to you from an external API, well then wrap them in a properly typed way. If you need the raw integral value of the enum members, just call an explicit conversion function then and there. But by the sound of it that should be when accessing the hardware itself, so these call sites can then also be wrapped and you'd be free to the right thing in all the layers above.

why std::string is not implicitly converted to bool

Is there a reason why in c++ std::string is not implicitly converted to bool? For example
std::string s = ""
if (s) { /* s in not empty */ }
as in other languages (e.g. python). I think it is tedious to use the empty method.
This probably could be added now that C++11 has added the concepts of explicit conversions and contextual conversion.
When std::string was designed, neither of these was present though. That made classes that supported conversion to bool fairly difficult to keep safe. In particular, that conversion could (and would) happen in lots of cases you almost never wanted it to. For example, if we assume std::string converts to false if empty and otherwise to true, then you could use a string essentially anywhere an integer or pointer was intended.
Rather than telling you about the type mismatch, the compiler would convert the string to bool, and then the bool to an integer (false -> 0, true -> 1).
Things like this happened often enough with many early attempts at string types (and there were many) that the committee apparently decided it was better to keep implicit conversions to an absolute minimum (so about the only implicit conversion supported by string is to create a string object from a C-style string).
There were a number of methods devised for handling conversion to bool more safely. One was converting to void * instead, which prevented some problems, but not others (this was used by iostreams). There was also a "safe bool" idiom (actually, more like a "safe bool" theme, of which there were several variations). While these certainly improved control over what conversions would and wouldn't be allowed, most of them involved a fair amount of overhead (a typical safe bool required a base class of ~50 lines of code, plus derivation from that base class, etc.)
As to how explicit conversion and contextual conversion would help, the basic idea is pretty simple. You can (starting with C++11) mark a conversion function as explicit, which allows it to be used only where an explicit cast to the target type is used:
struct X {
explicit operator bool() { return true; }
};
int main() {
X x;
bool b1 = static_cast<bool>(x); // compiles
bool b2 = x; // won't compile
}
Contextual conversion adds a little to let the conversion to bool happen implicitly, but only in something like an if statement, so using a class with the conversion function above, you'd get:
X x;
if (x) // allowed
int y = x; // would require explicit cast to compile
I'd add that complaints about "orthogonality" seem quite inapplicable here. Although convenient, converting a string to a Boolean doesn't really make a lot of sense. If anything, we should complain about how strange it is for string("0") to convert to 1 (in languages where that happens).
This article mentions some reasons why operator bool() can lead to surprising results.
Note that std::string is just a typedef for std::basic_string<char>. There is also std::wstring for multi-byte characters. An implicit conversion would let you write:
std::string foo = "foo";
std::wstring bar = "bar";
if (foo == bar) {
std::cout << "This will be printed, because both are true!\n";
}
std::string still has to coexist with C-style strings.
A C-style string is by definition "a contiguous sequence of characters terminated by and including the first null character", and is generally accessed via a pointer to its first character. An expression such as "hello, world" is, in most contexts, implicitly converted to a pointer to the first character. Such a pointer may then be implicitly converted to bool, yielding true if the pointer is non-null, false if it's null. (In C, it's not converted to bool, but it can still be used directly as a condition, so the effect is nearly the same.)
So, due to C++'s C heritage, if you write:
if ("") { ... }
the empty string is already treated as true, and that couldn't easily be changed without breaking C compatibility.
I suggest that having a C-style empty string evaluate as true and a C++ empty std::string evaluate as false would be too confusing.
And writing if (!s.empty()) isn't that difficult (and IMHO it's more legible).
The closest thing to what you (and I) want, that I've been able to find, is the following.
You can define the ! operator on std::string's like so:
bool operator!(const std::string& s)
{
return s.empty();
}
This allows you to do:
std::string s;
if (!s) // if |s| is empty
And using a simple negation, you can do:
if (!!s) // if |s| is not empty
That's a little awkward, but the question is, how badly do you want to avoid extra characters? !strcmp(...) is awkward, too, but we still functioned and got used to it, and many of us preferred it because it was faster than typing strcmp(...) == 0.
If anyone discovers a way to do if (s), in C++, please let us know.

How does multiplication work for C++ enums?

We have a template conversion function intended for use with numeric datatypes. Inside it contains a construct that makes it not compile with types like pointers.
template<class To, class From>
To ConvertTo( From what )
{
assert( 2 * what == what * 2 ); // this will not compile for pointers
//skipped
}
This function compiles and works allright when a enum is passed as the second template parameter:
enum TSomeEnum {
SE_First,
SE_Second
};
TSomeEnum enumValue = SE_First;
int result = ConvertTo<int>( enumValue );
The above code compiles and runs as intended on VC++7.
How does the operation * work for enums? Is it a way to undefined behaviour?
Enums degrade to ints (old C feature) so that why this is working. I don't think it's undefined behaviour although it might be the sort of behaviour you don't want/expect.
Enums are promoted to integers for arithmetic operations.
The values of enums are always numbered up from zero (this is part of the standard), but you can specify whatever values you like. Automatic numbering then procedes incrementally from the last item you explicitly numbered.
The compiler uses the smallest integral type that contains all of the values of an enum to store it.
eg:
enum foo
{
VALUE0, /* = 0 */
VALUE1, /* = 1 */
VALUE3 = 1234,
VALUE4 /* = 1235 */
};
I think peterchen has the ideal answer, but if boost is too much for you, change your current version to:
template<class To, class From>
To ConvertTo( From what, From checkConvertableToInt = 2 )
{
}
C++ doesn't allow implicit conversions from integers to enumerations. Similarly, it's only possible to implicitly convert the null pointer constant (0) to a pointer type.
Some of the other answers refer to an enumeration being implemented as an int or being promoted to an int. This is not true. In C++, an enumeration is defined to have an underlying type that is capable of storing all values in the enumeration. The following enumeration will therefore have an underlying type of 'unsigned int' or a larger signed/unsigned integral type:
enum E {
E0
, E1=MAX_INT+1u
};
The enumeration then follows the rules for its underlying type when you use it in an operation.
Timo described why it works.
For a safer test, you could use boost::TypeTraits
Richard Corden's answer gives a good mechanism to force enums to fail in the assert, however the side effect can cause problems, as you cannot be sure the code inside the assert will always run.
This test should probably by placed in a generic function to avoid the side effects.
template<class To, class From>
To ConvertTo( From what )
{
assert( testIntegralType(what) );
}
template<class T>
void testIntegralType( T val )
{
T v1 = val;
assert( 2*v1 == 2*val );
}
enums are stored as integers, and can even be cast to integers.
The compiler probably stored your above enum as
enum TSomeEnum {
SE_First = 0,
SE_SEcond = 1
};
I'm not sure if this numbering system is part of the C/C++ standard or just how compilers do it, but I've always seen them in order.
Anyway, to answer your question, since they're stored as ints underneath, it should be able to be multiplied. Some compilers may give you a warning about type conversion though.

Using elements of a constant array as cases in a switch statement

I'm attempting to map a set of key presses to a set of commands. Because I process the commands from several places, I'd like to set up a layer of abstraction between the keys and the commands so that if I change the underlying key mappings, I don't have to change very much code. My current attempt looks like this:
// input.h
enum LOGICAL_KEYS {
DO_SOMETHING_KEY,
DO_SOMETHING_ELSE_KEY,
...
countof_LOGICAL_KEYS
};
static const SDLKey LogicalMappings[countof_LOGICAL_KEYS] = {
SDLK_RETURN, // Do Something
SDLK_ESCAPE, // Do Something Else
...
};
// some_other_file.cpp
...
switch( event.key.keysym.key ) {
case LogicalMappings[ DO_SOMETHING_KEY ]:
doSomething();
break;
case LogicalMappings[ DO_SOMETHING_ELSE_KEY ]:
doSomethingElse();
break;
...
}
When I try to compile this (gcc 4.3.2) I get the error message:
error: 'LogicalMappings' cannot appear in a constant-expression
I don't see why the compiler has a problem with this. I understand why you're not allowed to have variables in a case statement, but I was under the impression that you could use constants, as they could be evaluated at compile-time. Do constant arrays not work with switch statements? If so, I suppose I could just replace the array with something like:
static const SDLKey LOGICAL_MAPPING_DO_SOMETHING = SDLK_RETURN;
static const SDLKey LOGICAL_MAPPING_DO_SOMETHING_ELSE = SDLK_ESCAPE;
...
But that seems much less elegant. Does anybody know why you can't use a constant array here?
EDIT: I've seen the bit of the C++ standard that claims that, "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)...". I still don't see why a constant array doesn't count as an "enumeration type initialized with a constant expression." It could just be that the answer to my question is "because that's the way that it is," and I'll have to work around it. But if that's the case, it's sort of disappointing, because the compiler really could determine those values at compile-time.
Referring to sections of the C++ standard: 6.4.2 requires that case expressions evaluate to an integral or enumeration constant. 5.19 defines what that is:
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. Floating literals (2.13.3) can appear only if they are cast to integral or enumeration types. Only type conversions to integral or enumeration types can be used. In particular, except in sizeof expressions, functions, class objects, pointers, or references shall not be used, and assignment, increment, decrement, function-call, or comma operators shall not be used.
So if your question was "why does the compiler reject this", one answer is "because the standard says so".
Array references aren't "constant enough", regardless.
You just need to do the mapping slightly differently. You want the same action to occur when the logical key is pressed, so use the logical key codes in the case clauses of the switch statement. Then map the actual key code to the logical code, possibly in the switch itself, or possibly before-hand. You can still use the LogicalMappings array, or a similar construct. And, as an aid to G11N (globalization), you can even make the mapping array non-constant so that different people can remap the keys to suit their needs.
I'll go on a limb here since nobody else replied to this and I've been mostly doing Java recently, not C++, but as far as I seem to recall an array lookup is not considered a constant integer even if the result of the lookup can be determined at compile time. This may even be an issue in the syntax.
Is there a comparison operator defined for the "LogicalMappings"? If not then that is the error.
There is a library called signal in boost that will help you create a event mapping abstraction.If you have time this should be better approach
you could also use an array of function pointers or functors (I suppose functor addresses), to avoid the switch statement altogether & just go from array index -> function pointer / functors directly.
for example (warning, untested code follows)
class Event // you probably have this defined already
{
}
class EventHandler // abstract base class
{
public:
virtual void operator()(Event& e) = 0;
};
class EventHandler1
{
virtual void operator()(Event& e){
// do something here
}
};
class EventHandler2
{
virtual void operator()(Event& e){
// do something here
}
};
EventHandler1 ev1;
EventHandler2 ev2;
EventHandler *LogicalMappings[countof_LOGICAL_KEYS] = {
&ev1,
&ev2,
// more here...
};
// time to use code:
Event event;
if (event.key.keysym.key < countof_LOGICAL_KEYS)
{
EventHandler *p = LogicalMappings[event.key.keysym.key];
if (p != NULL)
(*p)(event);
}
A compiler guru at work explained this to me. The problem is that the array itself is constant, but indices to it aren't necessarily const. Thus, the expression LogicalMappings[some_variable] couldn't be evaluated at compile-time, so the array winds up being stored in memory anyway rather than getting compiled out. There's still no reason why the compiler couldn't statically evaluate array references with a const or literal index, so what I want to do should theoretically be possible, but it's a bit trickier than I'd thought, so I can understand why gcc doesn't do it.