How to improve logic to check whether 4 boolean values match some cases
up vote
68
down vote
favorite
I have four bool
values:
bool bValue1;
bool bValue2;
bool bValue3;
bool bValue4;
The acceptable values are:
Scenario 1 | Scenario 2 | Scenario 3
bValue1: true | true | true
bValue2: true | true | false
bValue3: true | true | false
bValue4: true | false | false
So, for example, this scenario is not acceptable:
bValue1: false
bValue2: true
bValue3: true
bValue4: true
At the moment I have come up with this if
statement to detect bad scenarios:
if(((bValue4 && (!bValue3 || !bValue2 || !bValue1)) ||
((bValue3 && (!bValue2 || !bValue1)) ||
(bValue2 && !bValue1) ||
(!bValue1 && !bValue2 && !bValue3 && !bValue4))
{
// There is some error
}
Can that statement logic be improved/simplified?
c++ if-statement
|
show 13 more comments
up vote
68
down vote
favorite
I have four bool
values:
bool bValue1;
bool bValue2;
bool bValue3;
bool bValue4;
The acceptable values are:
Scenario 1 | Scenario 2 | Scenario 3
bValue1: true | true | true
bValue2: true | true | false
bValue3: true | true | false
bValue4: true | false | false
So, for example, this scenario is not acceptable:
bValue1: false
bValue2: true
bValue3: true
bValue4: true
At the moment I have come up with this if
statement to detect bad scenarios:
if(((bValue4 && (!bValue3 || !bValue2 || !bValue1)) ||
((bValue3 && (!bValue2 || !bValue1)) ||
(bValue2 && !bValue1) ||
(!bValue1 && !bValue2 && !bValue3 && !bValue4))
{
// There is some error
}
Can that statement logic be improved/simplified?
c++ if-statement
7
I would use a table instead of complexif
statement. Additionally, as these are boolean flags, you can model each scenario as a constant and check against it.
– Zdeslav Vojkovic
Dec 3 at 10:16
3
if (!((bValue1 && bValue2 && bValue3) || (bValue1 && !bValue2 && !bValue3 && !bValue4)))
– mch
Dec 3 at 10:17
13
what are the scenarios actually? Often things get much simpler if you just give stuff proper names, egbool scenario1 = bValue1 && bValue2 && bValue3 && bValue4;
– user463035818
Dec 3 at 10:57
4
Using meaningful names, you can extract each complex condition into a method and call that method in if condition. It would be much more readable and maintainable. e.g. Take a look at the example provided in the link.refactoring.guru/decompose-conditional
– Hardik Modha
Dec 3 at 12:29
3
FYI en.wikipedia.org/wiki/Karnaugh_map
– 00__00__00
yesterday
|
show 13 more comments
up vote
68
down vote
favorite
up vote
68
down vote
favorite
I have four bool
values:
bool bValue1;
bool bValue2;
bool bValue3;
bool bValue4;
The acceptable values are:
Scenario 1 | Scenario 2 | Scenario 3
bValue1: true | true | true
bValue2: true | true | false
bValue3: true | true | false
bValue4: true | false | false
So, for example, this scenario is not acceptable:
bValue1: false
bValue2: true
bValue3: true
bValue4: true
At the moment I have come up with this if
statement to detect bad scenarios:
if(((bValue4 && (!bValue3 || !bValue2 || !bValue1)) ||
((bValue3 && (!bValue2 || !bValue1)) ||
(bValue2 && !bValue1) ||
(!bValue1 && !bValue2 && !bValue3 && !bValue4))
{
// There is some error
}
Can that statement logic be improved/simplified?
c++ if-statement
I have four bool
values:
bool bValue1;
bool bValue2;
bool bValue3;
bool bValue4;
The acceptable values are:
Scenario 1 | Scenario 2 | Scenario 3
bValue1: true | true | true
bValue2: true | true | false
bValue3: true | true | false
bValue4: true | false | false
So, for example, this scenario is not acceptable:
bValue1: false
bValue2: true
bValue3: true
bValue4: true
At the moment I have come up with this if
statement to detect bad scenarios:
if(((bValue4 && (!bValue3 || !bValue2 || !bValue1)) ||
((bValue3 && (!bValue2 || !bValue1)) ||
(bValue2 && !bValue1) ||
(!bValue1 && !bValue2 && !bValue3 && !bValue4))
{
// There is some error
}
Can that statement logic be improved/simplified?
c++ if-statement
c++ if-statement
edited Dec 3 at 14:44
Dukeling
44.5k1060105
44.5k1060105
asked Dec 3 at 10:13
Andrew Truckle
5,16032145
5,16032145
7
I would use a table instead of complexif
statement. Additionally, as these are boolean flags, you can model each scenario as a constant and check against it.
– Zdeslav Vojkovic
Dec 3 at 10:16
3
if (!((bValue1 && bValue2 && bValue3) || (bValue1 && !bValue2 && !bValue3 && !bValue4)))
– mch
Dec 3 at 10:17
13
what are the scenarios actually? Often things get much simpler if you just give stuff proper names, egbool scenario1 = bValue1 && bValue2 && bValue3 && bValue4;
– user463035818
Dec 3 at 10:57
4
Using meaningful names, you can extract each complex condition into a method and call that method in if condition. It would be much more readable and maintainable. e.g. Take a look at the example provided in the link.refactoring.guru/decompose-conditional
– Hardik Modha
Dec 3 at 12:29
3
FYI en.wikipedia.org/wiki/Karnaugh_map
– 00__00__00
yesterday
|
show 13 more comments
7
I would use a table instead of complexif
statement. Additionally, as these are boolean flags, you can model each scenario as a constant and check against it.
– Zdeslav Vojkovic
Dec 3 at 10:16
3
if (!((bValue1 && bValue2 && bValue3) || (bValue1 && !bValue2 && !bValue3 && !bValue4)))
– mch
Dec 3 at 10:17
13
what are the scenarios actually? Often things get much simpler if you just give stuff proper names, egbool scenario1 = bValue1 && bValue2 && bValue3 && bValue4;
– user463035818
Dec 3 at 10:57
4
Using meaningful names, you can extract each complex condition into a method and call that method in if condition. It would be much more readable and maintainable. e.g. Take a look at the example provided in the link.refactoring.guru/decompose-conditional
– Hardik Modha
Dec 3 at 12:29
3
FYI en.wikipedia.org/wiki/Karnaugh_map
– 00__00__00
yesterday
7
7
I would use a table instead of complex
if
statement. Additionally, as these are boolean flags, you can model each scenario as a constant and check against it.– Zdeslav Vojkovic
Dec 3 at 10:16
I would use a table instead of complex
if
statement. Additionally, as these are boolean flags, you can model each scenario as a constant and check against it.– Zdeslav Vojkovic
Dec 3 at 10:16
3
3
if (!((bValue1 && bValue2 && bValue3) || (bValue1 && !bValue2 && !bValue3 && !bValue4)))
– mch
Dec 3 at 10:17
if (!((bValue1 && bValue2 && bValue3) || (bValue1 && !bValue2 && !bValue3 && !bValue4)))
– mch
Dec 3 at 10:17
13
13
what are the scenarios actually? Often things get much simpler if you just give stuff proper names, eg
bool scenario1 = bValue1 && bValue2 && bValue3 && bValue4;
– user463035818
Dec 3 at 10:57
what are the scenarios actually? Often things get much simpler if you just give stuff proper names, eg
bool scenario1 = bValue1 && bValue2 && bValue3 && bValue4;
– user463035818
Dec 3 at 10:57
4
4
Using meaningful names, you can extract each complex condition into a method and call that method in if condition. It would be much more readable and maintainable. e.g. Take a look at the example provided in the link.refactoring.guru/decompose-conditional
– Hardik Modha
Dec 3 at 12:29
Using meaningful names, you can extract each complex condition into a method and call that method in if condition. It would be much more readable and maintainable. e.g. Take a look at the example provided in the link.refactoring.guru/decompose-conditional
– Hardik Modha
Dec 3 at 12:29
3
3
FYI en.wikipedia.org/wiki/Karnaugh_map
– 00__00__00
yesterday
FYI en.wikipedia.org/wiki/Karnaugh_map
– 00__00__00
yesterday
|
show 13 more comments
28 Answers
28
active
oldest
votes
up vote
150
down vote
accepted
I would aim for readability: you have just 3 scenario, deal with them with 3 separate ifs:
bool valid = false;
if (bValue1 && bValue2 && bValue3 && bValue4)
valid = true; //scenario 1
else if (bValue1 && bValue2 && bValue3 && !bValue4)
valid = true; //scenario 2
else if (bValue1 && !bValue2 && !bValue3 && !bValue4)
valid = true; //scenario 3
Easy to read and debug, IMHO. Also, you can assign a variable whichScenario
while proceeding with the if
.
With just 3 scenarios, I would not go with something such "if the first 3 values are true I can avoid check the forth value": it's going to make your code harder to read and maintain.
Not an elegant solution maybe, but in this case is ok: easy and readable.
If your logic gets more complicated, consider using something more to store different available scenarios (as Zladeck is suggesting).
4
Damn, simplicity is a virtue. I think this is the best answer, far better than mine or any other obfuscating technique! Bravo!
– gsamaras
Dec 3 at 10:34
1
sure @hessamhedieh, it's ok only for a small number of available scenario. as I said, if things get more complicated, better look for something else
– Gian Paolo
Dec 3 at 10:49
2
This can be simplified further by stacking all conditions into the initializer forvalid
and separating them with||
, rather than mutatingvalid
within separate statement blocks. I can't put an example in the comment but you can vertically align the||
operators along the left to make this very clear; the individual conditions are already parenthesized as much as they need to be (forif
) so you don't need to add any characters to the expressions beyond what is already there.
– Leushenko
Dec 3 at 11:13
1
@Leushenko, I think that mixing parenthesis, && and || conditions is quite error prone (someone in a different answer said there was an error in parenthesis in the code in OP, maybe it has been corrected). Proper alignment can help, sure. But what is the advantage? more readable? easier to maintain? I don't think so. Just my opinion, of course. An be sure, I really hate having lot of ifs in code.
– Gian Paolo
Dec 3 at 12:43
3
I'd've wrapped it in aif($bValue1)
as that always has to be true, technically allowing some minor performance improvement (though we're talking about negligable amounts here).
– Martijn
Dec 3 at 14:36
|
show 13 more comments
up vote
80
down vote
We can use a Karnaugh map and reduce your scenarios to a logical equation.
I have used the Online Karnaugh map solver with circuit for 4 variables.
This yields:
Changing A, B, C, D
to bValue1, bValue2, bValue3, bValue4
, this is nothing but:
bValue1 && bValue2 && bValue3 || bValue1 && !bValue2 && !bValue3 && !bValue4
So your if
statement becomes:
if(!(bValue1 && bValue2 && bValue3 || bValue1 && !bValue2 && !bValue3 && !bValue4))
{
// There is some error
}
- Karnaugh Maps are particularly useful when you have many variables and many conditions which should evaluate
true
. - After reducing the
true
scenarios to a logical equation, adding relevant comments indicating thetrue
scenarios is good practice.
82
Though technically correct, this code requires a lot of comments in order to be edited by another developer few months later.
– Zdeslav Vojkovic
Dec 3 at 11:00
15
@ZdeslavVojkovic: I would just add a comment with the equation.//!(ABC + AB'C'D') (By K-Map logic)
. That would be a good time for the developer to learn K-Maps if he doesn't already know them.
– P.W
Dec 3 at 11:05
9
I agree with that, but IMO the problem is that it doesn't map clearly to the problem domain, i.e. how each condition maps to specific scenario which makes it hard to change/extend. What happens when there areE
andF
conditions and 4 new scenarios? How long it takes to update thisif
statement correctly? How does code review check if it is ok or not? The problem is not with the technical side but with "business" side.
– Zdeslav Vojkovic
Dec 3 at 11:09
7
I think you can factor outA
:ABC + AB'C'D' = A(BC + B'C'D')
(this can be even factored toA(B ^ C)'(C + D')
though I'd be careful with calling this 'simplification').
– Maciej Piechotka
Dec 3 at 11:31
18
@P.W That comment seems about as understandable as the code, and is thus a bit pointless. A better comment would explain how you actually came up with that equation, i.e. that the statement should trigger for TTTT, TTTF and TFFF. At that point you might as well just write those three conditions in the code instead and not need an explanation at all.
– Dukeling
Dec 3 at 14:21
|
show 10 more comments
up vote
72
down vote
I would aim for simplicity and readability.
bool scenario1 = bValue1 && bValue2 && bValue3 && bValue4;
bool scenario2 = bValue1 && bValue2 && bValue3 && !bValue4;
bool scenario3 = bValue1 && !bValue2 && !bValue3 && !bValue4;
if (scenario1 || scenario2 || scenario3) {
// Do whatever.
}
Make sure to replace the names of the scenarios as well as the names of the flags with something descriptive. If it makes sense for your specific problem, you could consider this alternative:
bool scenario1or2 = bValue1 && bValue2 && bValue3;
bool scenario3 = bValue1 && !bValue2 && !bValue3 && !bValue4;
if (scenario1or2 || scenario3) {
// Do whatever.
}
What's important here is not predicate logic or Karnaugh maps. It's describing your domain and clearly expressing your intent. The key here is to give all inputs and intermediary variables good names. If you can't find good variable names, it may be a sign that you are describing the problem in the wrong way.
3
+1 I am surprised there are 0 upvotes here. The solution is short, self-documenting (no comments needed), and easy to modify with little chance of introducing bugs. A clear favourite.
– RedFilter
2 days ago
2
Thanks for this. In my solution that I provided as an answer I also took onboard what you said. The only different being that I moved the scenarios into methods.
– Andrew Truckle
yesterday
+1 This is what I would have done as well. Just like @RedFilter points out, and in contrast to the accepted answer, this is self-documenting. Giving the scenarios their own names in a separate step is much more readable.
– Andreas
yesterday
add a comment |
up vote
45
down vote
The real question here is: what happens when another developer (or even author) must change this code few months later.
I would suggest modelling this as bit flags:
const int SCENARIO_1 = 0x0F; // 0b1111 if using c++14
const int SCENARIO_2 = 0x0E; // 0b1110
const int SCENARIO_3 = 0x08; // 0b1000
bool bValue1 = true;
bool bValue2 = false;
bool bValue3 = false;
bool bValue4 = false;
// boolean -> int conversion is covered by standard and produces 0/1
int scenario = bValue1 << 3 | bValue2 << 2 | bValue3 << 1 | bValue4;
bool match = scenario == SCENARIO_1 || scenario == SCENARIO_2 || scenario == SCENARIO_3;
std::cout << (match ? "ok" : "error");
If there are many more scenarios or more flags, a table approach is more readable and extensible than using flags. Supporting a new scenario requires just another row in the table.
int scenarios[3][4] = {
{true, true, true, true},
{true, true, true, false},
{true, false, false, false},
};
int main()
{
bool bValue1 = true;
bool bValue2 = false;
bool bValue3 = true;
bool bValue4 = true;
bool match = false;
// depending on compiler, prefer std::size()/_countof instead of magic value of 4
for (int i = 0; i < 4 && !match; ++i) {
auto current = scenarios[i];
match = bValue1 == current[0] &&
bValue2 == current[1] &&
bValue3 == current[2] &&
bValue4 == current[3];
}
std::cout << (match ? "ok" : "error");
}
3
Not the most maintainable but definitely simplifies the if condition. So leaving a few comments around the bitwise operations will be an absolute necessity here imo.
– Adam Zahran
Dec 3 at 10:35
5
IMO, table is the best approach as it scales better with additional scenarios and flags.
– Zdeslav Vojkovic
Dec 3 at 10:44
I like your first solution, easy to read and open to modification. I would make 2 improvements: 1: assign values to scenarioX with an explicit indication of boolean values used, e.g.SCENARIO_2 = true << 3 | true << 2 | true << 1 | false;
2: avoid SCENARIO_X variables and then store all available scenarios in a<std::set<int>
. Adding a scenario is going to be just something asmySet.insert( true << 3 | false << 2 | true << 1 | false;
maybe a little overkill for just 3 scenario, OP accepted the quick, dirty and easy solution I suggested in my answer.
– Gian Paolo
Dec 3 at 12:52
4
If you're using C++14 or higher, I'd suggest instead using binary literals for the first solution - 0b1111, 0b1110 and 0b1000 is much clearer. You can probably also simplify this a bit using the standard library (std::find
?).
– Dukeling
Dec 3 at 14:25
2
I find that binary literals here would be a minimal requirement to make the first code clean. In its current form it’s completely cryptic. Descriptive identifiers might help but I’m not even sure about that. In fact, the bit operations to produce thescenario
value strike me as unnecessarily error-prone.
– Konrad Rudolph
Dec 3 at 22:25
add a comment |
up vote
17
down vote
My previous answer is already the accepted answer, I add something here that I think is both readable, easy and in this case open to future modifications:
Starting with @ZdeslavVojkovic answer (which I find quite good), I came up with this:
#include <iostream>
#include <set>
//using namespace std;
int GetScenarioInt(bool bValue1, bool bValue2, bool bValue3, bool bValue4)
{
return bValue1 << 3 | bValue2 << 2 | bValue3 << 1 | bValue4;
}
bool IsValidScenario(bool bValue1, bool bValue2, bool bValue3, bool bValue4)
{
std::set<int> validScenarios;
validScenarios.insert(GetScenarioInt(true, true, true, true));
validScenarios.insert(GetScenarioInt(true, true, true, false));
validScenarios.insert(GetScenarioInt(true, false, false, false));
int currentScenario = GetScenarioInt(bValue1, bValue2, bValue3, bValue4);
return validScenarios.find(currentScenario) != validScenarios.end();
}
int main()
{
std::cout << IsValidScenario(true, true, true, false) << "n"; // expected = true;
std::cout << IsValidScenario(true, true, false, false) << "n"; // expected = false;
return 0;
}
See it at work here
Well, that's the "elegant and maintainable" (IMHO) solution I usually aim to, but really, for the OP case, my previous "bunch of ifs" answer fits better the OP requirements, even if it's not elegant nor maintainable.
(Almost) off topic:
I don't write lot of answers here at StackOverflow. It's really funny that the above accepted anwser is the most appreciated answer in my history, granting me a couple of badges at SO.
And actually is not what I usually think is the "right" way to do it.
But simplicity is often "the right way to do it", many people seems to think this and I should think it more than I do :)
10
I'd consider removing the last 3 paragraphs as they add nothing to your answer. Consider editing your other answer to add the part about "simplicity is often / always the right way to do something. Readability/maintainability beats a few lines saved".
– Tas
Dec 3 at 21:13
add a comment |
up vote
13
down vote
I would also like to submit an other approach.
My idea is to convert the bools into an integer and then compare using variadic templates:
unsigned bitmap_from_bools(bool b) {
return b;
}
template<typename... args>
unsigned bitmap_from_bools(bool b, args... pack) {
return (bitmap_from_bools(b) << sizeof...(pack)) | bitmap_from_bools(pack...);
}
int main() {
bool bValue1;
bool bValue2;
bool bValue3;
bool bValue4;
unsigned summary = bitmap_from_bools(bValue1, bValue2, bValue3, bValue4);
if (summary != 0b1111u && summary != 0b1110u && summary != 0b1000u) {
//bad scenario
}
}
Notice how this system can support up to 32 bools as input. replacing the unsigned
with unsigned long long
(or uint64_t
) increases support to 64 cases.
If you dont like the if (summary != 0b1111u && summary != 0b1110u && summary != 0b1000u)
, you could also use yet another variadic template method:
bool equals_any(unsigned target, unsigned compare) {
return target == compare;
}
template<typename... args>
bool equals_any(unsigned target, unsigned compare, args... compare_pack) {
return equals_any(target, compare) ? true : equals_any(target, compare_pack...);
}
int main() {
bool bValue1;
bool bValue2;
bool bValue3;
bool bValue4;
unsigned summary = bitmap_from_bools(bValue1, bValue2, bValue3, bValue4);
if (!equals_any(summary, 0b1111u, 0b1110u, 0b1000u)) {
//bad scenario
}
}
3
Thanks for sharing your alternative approach.
– Andrew Truckle
Dec 3 at 12:39
1
I love this approach, except for the main function’s name: “from bool … to what?” — Why not explicitly,bitmap_from_bools
, orbools_to_bitmap
?
– Konrad Rudolph
Dec 3 at 22:29
yes @KonradRudolph, I couldn't think of a better name, except maybebools_to_unsigned
. Bitmap is a good keyword; edited.
– Stack Danny
2 days ago
I think you wantsummary!= 0b1111u &&...
.a != b || a != c
is always true ifb != c
– MooseBoys
yesterday
@MooseBoys yes, you're right. Thanks
– Stack Danny
yesterday
add a comment |
up vote
11
down vote
Here's a simplified version:
if (bValue1&&(bValue2==bValue3)&&(bValue2||!bValue4)) {
// acceptable
} else {
// not acceptable
}
Note, of course, this solution is more obfuscated than the original one, its meaning may be harder to understand.
Update: MSalters in the comments found an even simpler expression:
if (bValue1&&(bValue2==bValue3)&&(bValue2>=bValue4)) ...
Yes, but hard to understand. But thanks for suggestion.
– Andrew Truckle
Dec 3 at 10:58
I compared compilers ability to simplify expression with your simplification as a reference: compiler explorer. gcc did not find your optimal version but its solution is still good. Clang and MSVC don't seem to perform any boolean expression simplification.
– Oliv
Dec 3 at 11:07
1
@AndrewTruckle: note, that if you needed a more readable version, then please say so. You've said "simplified", yet you accept an even more verbose version than your original one.
– geza
Dec 3 at 11:12
@Oliv: thanks for doing this test! This proves the point that while compilers are getting better and better, they still have a lot to learn :)
– geza
Dec 3 at 11:15
1
simple
is indeed a vague term. Many people understand it in this context as simpler for developer to understand and not for the compiler to generate code, so more verbose can indeed be simpler.
– Zdeslav Vojkovic
Dec 3 at 11:16
|
show 5 more comments
up vote
7
down vote
I'm not seeing any answers saying to name the scenarios, though the OP's solution does exactly that.
To me it is best to encapsulate the comment of what each scenario is into either a variable name or function name. You're more likely to ignore a comment than a name, and if your logic changes in the future you're more likely to change a name than a comment. You can't refactor a comment.
If you plan on reusing these scenarios outside of your function (or might want to), then make a function that says what it evaluates (constexpr
/noexcept
optional but recommended):
constexpr bool IsScenario1(bool b1, bool b2, bool b3, bool b4) noexcept
{ return b1 && b2 && b3 && b4; }
constexpr bool IsScenario2(bool b1, bool b2, bool b3, bool b4) noexcept
{ return b1 && b2 && b3 && !b4; }
constexpr bool IsScenario3(bool b1, bool b2, bool b3, bool b4) noexcept
{ return b1 && !b2 && !b3 && !b4; }
Make these class methods if possible (like in OP's solution). You can use variables inside of your function if you don't think you'll reuse the logic:
const auto is_scenario_1 = bValue1 && bValue2 && bValue3 && bValue4;
const auto is_scenario_2 = bvalue1 && bvalue2 && bValue3 && !bValue4;
const auto is_scenario_3 = bValue1 && !bValue2 && !bValue3 && !bValue4;
The compiler will most likely sort out that if bValue1 is false then all scenarios are false. Don't worry about making it fast, just correct and readable. If you profile your code and find this to be a bottleneck because the compiler generated sub-optimal code at -O2 or higher then try to rewrite it.
I like this slightly more than Gian Paolo's (already nice) solution: It avoids control flow and the use of a variable that is overwritten - more functional style.
– Dirk Herrmann
Dec 3 at 23:53
add a comment |
up vote
6
down vote
I am only providing my answer here as in the comments someone suggested to show my solution. I want to thank everyone for their insights.
In the end I opted to add three new "scenario" boolean
methods:
bool CChristianLifeMinistryValidationDlg::IsFirstWeekStudentItems(CChristianLifeMinistryEntry *pEntry)
{
return (INCLUDE_ITEM1(pEntry) &&
!INCLUDE_ITEM2(pEntry) &&
!INCLUDE_ITEM3(pEntry) &&
!INCLUDE_ITEM4(pEntry));
}
bool CChristianLifeMinistryValidationDlg::IsSecondWeekStudentItems(CChristianLifeMinistryEntry *pEntry)
{
return (INCLUDE_ITEM1(pEntry) &&
INCLUDE_ITEM2(pEntry) &&
INCLUDE_ITEM3(pEntry) &&
INCLUDE_ITEM4(pEntry));
}
bool CChristianLifeMinistryValidationDlg::IsOtherWeekStudentItems(CChristianLifeMinistryEntry *pEntry)
{
return (INCLUDE_ITEM1(pEntry) &&
INCLUDE_ITEM2(pEntry) &&
INCLUDE_ITEM3(pEntry) &&
!INCLUDE_ITEM4(pEntry));
}
Then I was able to apply those my my validation routine like this:
if (!IsFirstWeekStudentItems(pEntry) && !IsSecondWeekStudentItems(pEntry) && !IsOtherWeekStudentItems(pEntry))
{
; Error
}
In my live application the 4 bool values are actually extracted from a DWORD
which has 4 values encoded into it.
Thanks again everyone.
1
Thanks for sharing the solution. :) It's actually better than the complex if conditions hell. Maybe you can still nameINCLUDE_ITEM1
etc in a better way and you are all good. :)
– Hardik Modha
Dec 3 at 13:04
1
@HardikModha Well, technically they are "Student items" and the flag is to indicate if they are to be "included". So I think the name, albeit sounding generic, is actually meaningful in this context. :)
– Andrew Truckle
Dec 3 at 13:06
Well, Sounds good then. :)
– Hardik Modha
Dec 3 at 13:10
add a comment |
up vote
5
down vote
A C/C++ way
bool scenario[3][4] = {{true, true, true, true},
{true, true, true, false},
{true, false, false, false}};
bool CheckScenario(bool bValue1, bool bValue2, bool bValue3, bool bValue4)
{
bool temp = {bValue1, bValue2, bValue3, bValue4};
for(int i = 0 ; i < sizeof(scenario) / sizeof(scenario[0]); i++)
{
if(memcmp(temp, scenario[i], sizeof(temp)) == 0)
return true;
}
return false;
}
This approach is scalable as if the number of valid conditions grow, you easily just add more of them to scenario list.
Thank you for your answer.
– Andrew Truckle
Dec 3 at 12:36
I'm pretty sure this is wrong, though. It assumes that the compiler uses only a single binary representation fortrue
. A compiler which uses "anything non-zero is true" causes this code to fail. Note thattrue
must convert to1
, it just doesn't need to be stored as such.
– MSalters
Dec 3 at 15:43
@MSalters, tnx, I get your point and I am aware of that, kinda like2 is not equal to true but evaluates to true
, my code doesnt forceint 1 = true
and works as long as all true's are converted to same int value, SO here is my question: Why compiler should act random on converting true to underlying int, Can you please elaborate more?
– hessam hedieh
Dec 3 at 16:01
Performing amemcmp
to test boolean conditions is not the C++ way, and I rather doubt that it’s an established C way, either.
– Konrad Rudolph
Dec 3 at 22:27
@hessamhedieh: The problem in your logic is "converting true to underlying int". That is not how compilers work,
– MSalters
2 days ago
|
show 1 more comment
up vote
5
down vote
It's easy to notice that first two scenarios are similar - they share most of the conditions. If you want to select in which scenario you are at the moment, you could write it like this (it's a modified @gian-paolo's solution):
bool valid = false;
if(bValue1 && bValue2 && bValue3)
{
if (bValue4)
valid = true; //scenario 1
else if (!bValue4)
valid = true; //scenario 2
}
else if (bValue1 && !bValue2 && !bValue3 && !bValue4)
valid = true; //scenario 3
Going further, you can notice, that first boolean needs to be always true, which is an entry condition, so you can end up with:
bool valid = false;
if(bValue1)
{
if(bValue2 && bValue3)
{
if (bValue4)
valid = true; //scenario 1
else if (!bValue4)
valid = true; //scenario 2
}
else if (!bValue2 && !bValue3 && !bValue4)
valid = true; //scenario 3
}
Even more, you can now clearly see, that bValue2 and bValue3 are somewhat connected - you could extract their state to some external functions or variables with more appropriate name (this is not always easy or appropriate though):
bool valid = false;
if(bValue1)
{
bool bValue1and2 = bValue1 && bValue2;
bool notBValue1and2 = !bValue2 && !bValue3;
if(bValue1and2)
{
if (bValue4)
valid = true; //scenario 1
else if (!bValue4)
valid = true; //scenario 2
}
else if (notBValue1and2 && !bValue4)
valid = true; //scenario 3
}
Doing it this way have some advantages and disadvantages:
- conditions are smaller, so it's easier to reason about them,
- it's easier to do nice renaming to make these conditions more understandable,
- but, they require to understand the scope,
- moreover it's more rigid
If you predict that there will be changes to the above logic, you should use more straightforward approach as presented by @gian-paolo.
Otherwise, if these conditions are well established, and are kind of "solid rules" that will never change, consider my last code snippet.
add a comment |
up vote
5
down vote
Consider translating your tables as directly as possible into your program. Drive the program based off the table, instead of mimicing it with logic.
template<class T0>
auto is_any_of( T0 const& t0, std::initializer_list<T0> il ) {
for (auto&& x:il)
if (x==t0) return true;
return false;
}
now
if (is_any_of(
std::make_tuple(bValue1, bValue2, bValue3, bValue4),
{
{true, true, true, true},
{true, true, true, false},
{true, false, false, false}
}
))
this directly as possible encodes your truth table into the compiler.
Live example.
You could also use std::any_of
directly:
using entry = std::array<bool, 4>;
constexpr entry acceptable =
{
{true, true, true, true},
{true, true, true, false},
{true, false, false, false}
};
if (std::any_of( begin(acceptable), end(acceptable), [&](auto&&x){
return entry{bValue1, bValue2, bValue3, bValue4} == x;
}) {
}
the compiler can inline the code, and eliminate any iteration and build its own logic for you. Meanwhile, your code reflects exactly how you concieved of the problem.
The first version is so easy to read and so maintenable, I really like it. The second one is harder to read, at least for me, and requires a c++ skill level maybe over the average, surely over my one. Not something everyone is able to write. Just learned somethin new, thanks
– Gian Paolo
2 days ago
Interesting alternative. 👍
– Andrew Truckle
yesterday
add a comment |
up vote
3
down vote
I would also use shortcut variables for clarity. As noted earlier scenario 1 equals to scenario 2, because the value of bValue4 doesn't influence the truth of those two scenarios.
bool MAJORLY_TRUE=bValue1 && bValue2 && bValue3
bool MAJORLY_FALSE=!(bValue2 || bValue3 || bValue4)
then your expression beomes:
if (MAJORLY_TRUE || (bValue1 && MAJORLY_FALSE))
{
// do something
}
else
{
// There is some error
}
Giving meaningful names to MAJORTRUE and MAJORFALSE variables (as well as actually to bValue* vars) would help a lot with readability and maintenance.
add a comment |
up vote
3
down vote
As suggested by mch, you could do:
if(!((bValue1 && bValue2 && bValue3) ||
(bValue1 && !bValue2 && !bValue3 && !bValue4))
)
where the first line covers the two first good cases, and the second line covers the last one.
Live Demo, where I played around and it passes your cases.
add a comment |
up vote
3
down vote
Focus on readability of the problem, not the specific "if" statement.
While this will produce more lines of code, and some may consider it either overkill or unnecessary. I'd suggest that abstracting your scenarios from the specific booleans is the best way to maintain readability.
By splitting things into classes (feel free to just use functions, or whatever other tool you prefer) with understandable names - we can much more easily show the meanings behind each scenario. More importantly, in a system with many moving parts - it is easier to maintain and join into your existing systems (again, despite how much extra code is involed).
#include <iostream>
#include <vector>
using namespace std;
// These values would likely not come from a single struct in real life
// Instead, they may be references to other booleans in other systems
struct Values
{
bool bValue1; // These would be given better names in reality
bool bValue2; // e.g. bDidTheCarCatchFire
bool bValue3; // and bDidTheWindshieldFallOff
bool bValue4;
};
class Scenario
{
public:
Scenario(Values& values)
: mValues(values) {}
virtual operator bool() = 0;
protected:
Values& mValues;
};
// Names as examples of things that describe your "scenarios" more effectively
class Scenario1_TheCarWasNotDamagedAtAll : public Scenario
{
public:
Scenario1_TheCarWasNotDamagedAtAll(Values& values) : Scenario(values) {}
virtual operator bool()
{
return mValues.bValue1
&& mValues.bValue2
&& mValues.bValue3
&& mValues.bValue4;
}
};
class Scenario2_TheCarBreaksDownButDidntGoOnFire : public Scenario
{
public:
Scenario2_TheCarBreaksDownButDidntGoOnFire(Values& values) : Scenario(values) {}
virtual operator bool()
{
return mValues.bValue1
&& mValues.bValue2
&& mValues.bValue3
&& !mValues.bValue4;
}
};
class Scenario3_TheCarWasCompletelyWreckedAndFireEverywhere : public Scenario
{
public:
Scenario3_TheCarWasCompletelyWreckedAndFireEverywhere(Values& values) : Scenario(values) {}
virtual operator bool()
{
return mValues.bValue1
&& !mValues.bValue2
&& !mValues.bValue3
&& !mValues.bValue4;
}
};
Scenario* findMatchingScenario(std::vector<Scenario*>& scenarios)
{
for(std::vector<Scenario*>::iterator it = scenarios.begin(); it != scenarios.end(); it++)
{
if (**it)
{
return *it;
}
}
return NULL;
}
int main() {
Values values = {true, true, true, true};
std::vector<Scenario*> scenarios = {
new Scenario1_TheCarWasNotDamagedAtAll(values),
new Scenario2_TheCarBreaksDownButDidntGoOnFire(values),
new Scenario3_TheCarWasCompletelyWreckedAndFireEverywhere(values)
};
Scenario* matchingScenario = findMatchingScenario(scenarios);
if(matchingScenario)
{
std::cout << matchingScenario << " was a match" << std::endl;
}
else
{
std::cout << "No match" << std::endl;
}
// your code goes here
return 0;
}
5
At some point, verbosity starts to harm readability. I think this goes too far.
– JollyJoker
Dec 3 at 13:01
2
@JollyJoker I do actually agree in this specific situation - however, my gut feeling from the way OP has named everything extremely generically, is that their "real" code is likely a lot more complex than the example they've given. Really, I just wanted to put this alternative out there, as it's how I'd structure it for something far more complex/involved. But you're right - for OPs specific example, it is overly verbose and makes matters worse.
– Bilkokuya
Dec 3 at 13:30
add a comment |
up vote
3
down vote
A slight variation on @GianPaolo's fine answer, which some may find easier to read:
bool any_of_three_scenarios(bool v1, bool v2, bool v3, bool v4)
{
return (v1 && v2 && v3 && v4) // scenario 1
|| (v1 && v2 && v3 && !v4) // scenario 2
|| (v1 && !v2 && !v3 && !v4); // scenario 3
}
if (any_of_three_scenarios(bValue1,bValue2,bValue3,bValue4))
{
// ...
}
add a comment |
up vote
3
down vote
It depends on what they represent.
For example if 1 is a key, and 2 and 3 are two people who must agree (except if they agree on NOT
they need a third person - 4 - to confirm) the most readable might be:
1 &&
(
(2 && 3)
||
((!2 && !3) && !4)
)
by popular request:
Key &&
(
(Alice && Bob)
||
((!Alice && !Bob) && !Charlie)
)
2
You might be right, but using numbers to illustrate your point detracts from your answer. Try using descriptive names.
– jxh
Dec 3 at 22:45
1
@jxh Those are the numbers OP used. I just removed thebValue
.
– ispiro
Dec 3 at 23:26
@jxh I hope it's better now.
– ispiro
yesterday
add a comment |
up vote
3
down vote
Every answer is overly complex and difficult to read. The best solution to this is a switch()
statement. It is both readable and makes adding/modifying additional cases simple. Compilers are good at optimising switch()
statements too.
switch( (bValue4 << 3) | (bValue3 << 2) | (bValue2 << 1) | (bValue1) )
{
case 0b1111:
// scenario 1
break;
case 0b0111:
// scenario 2
break;
case 0b0001:
// scenario 3
break;
default:
// fault condition
break;
}
You can of course use constants and OR them together in the case
statements for even greater readability.
Being an old C-programmer, I'd define a "PackBools" macro and use that both for the "switch(PackBools(a,b,c,d))" and for the cases, eg either directly "case PackBools(true, true...)" or define them as local constants.e.g. "const unsigned int scenario1 = PackBools(true, true...);"
– Simon F
13 hours ago
add a comment |
up vote
2
down vote
I am denoting a, b, c, d for clarity, and A, B, C, D for complements
bValue1 = a (!A)
bValue2 = b (!B)
bValue3 = c (!C)
bValue4 = d (!D)
Equation
1 = abcd + abcD + aBCD
= a (bcd + bcD + BCD)
= a (bc + BCD)
= a (bcd + D (b ^C))
Use any equations that suits you.
add a comment |
up vote
2
down vote
If (!bValue1 || (bValue2 != bValue3) || (!bValue4 && bValue2))
{
// you have a problem
}
- b1 must always be true
- b2 must always equal b3
- and b4 cannot be false
if b2 (and b3) are true
simple
New contributor
add a comment |
up vote
2
down vote
Doing bitwise operation looks very clean and understandable.
int bitwise = (bValue4 << 3) | (bValue3 << 2) | (bValue2 << 1) | (bValue1);
if (bitwise == 0b1111 || bitwise == 0b0111 || bitwise == 0b0001)
{
//satisfying condition
}
The bitwise comparison looks readable to me. The composition, on the other hand, looks artificial.
– xtofl
yesterday
add a comment |
up vote
1
down vote
First, assuming you can only modify the scenario check, I would focus on readability and just wrap the check in a function so that you can just call if(ScenarioA())
.
Now, assuming you actually want/need to optimize this, I would recommend converting the tightly linked Booleans into constant integers, and using bit operators on them
public class Options {
public const bool A = 2; // 0001
public const bool B = 4; // 0010
public const bool C = 16;// 0100
public const bool D = 32;// 1000
//public const bool N = 2^n; (up to n=32)
}
...
public isScenario3(int options) {
int s3 = Options.A | Options.B | Options.C;
// for true if only s3 options are set
return options == s3;
// for true if s3 options are set
// return options & s3 == s3
}
This makes expressing the scenarios as easy as listing what is part of it, allows you to use a switch statement to jump to the right condition, and confuse fellow developers who have not seen this before. (C# RegexOptions uses this pattern for setting flags, I don't know if there is a c++ library example)
In actual fact I am not using four bool values but a DWORD with four embedded BOOLS. Too late to change it now. But thanks for your suggestion.
– Andrew Truckle
yesterday
add a comment |
up vote
1
down vote
Nested if
s could be easier to read for some people. Here is my version
bool check(int bValue1, int bValue2, int bValue3, int bValue4)
{
if (bValue1)
{
if (bValue2)
{
// scenario 1-2
return bValue3;
}
else
{
// scenario 3
return !bValue3 && !bValue4;
}
}
return false;
}
Another interesting variation. Thank you.
– Andrew Truckle
yesterday
Personally, I'd usually avoid nesting if statements if possible. While this case is nice and readable, once new possibilities are added, the nesting can become very hard to read. But if the scenarios never change, it definitly is a nice and readable solution.
– Dnomyar96
16 hours ago
@Dnomyar96 i agree. I personally avoid nested ifs too. Sometimes if the logic is complicated, it is easier for me to understand the logic by breaking it down into the pieces. For example, once you enterbValue1
block, then you may treat everything in it as a new fresh page in your mental process. I bet the way of approaching to the problem may be very personal or even cultural thing.
– sardok
16 hours ago
add a comment |
up vote
0
down vote
My 2 cents: declare a variable sum (integer) so that
if(bValue1)
{
sum=sum+1;
}
if(bValue2)
{
sum=sum+2;
}
if(bValue3)
{
sum=sum+4;
}
if(bValue4)
{
sum=sum+8;
}
Check sum against the conditions you want and that's it.
This way you can add easily more conditions in the future keeping it quite straightforward to read.
add a comment |
up vote
0
down vote
You won't have to worry about invalid combinations of boolean flags if you get rid of the boolean flags.
The acceptable values are:
Scenario 1 | Scenario 2 | Scenario 3
bValue1: true | true | true
bValue2: true | true | false
bValue3: true | true | false
bValue4: true | false | false
You clearly have three states. It'd be better to model that and to derive the boolean properties from those states, not the other way around.
enum State
{
scenario1,
scenario2,
scenario3,
};
bool isValue1(State s)
{
// (Well, this is kind of silly. Do you really need this flag?)
return true;
}
bool isValue2(State s)
{
switch (s)
{
case scenario1:
case scenario2:
return true;
case scenario3:
return false;
}
}
bool isValue3(State s)
{
// (This is silly too. Do you really need this flag?)
return isValue2(s);
}
bool isValue4(State s)
{
switch (s)
{
case scenario1:
return true;
case scenario2:
case scenario3:
return false;
}
}
If your boolean values can change dynamically, then instead of toggling individual boolean flags (which could result in invalid combinations of flags), you instead can have a state machine that transitions from one scenario to another.
add a comment |
up vote
0
down vote
Just a personal preference over the accepted answer, but I would write:
bool valid = false;
// scenario 1
valid = valid || (bValue1 && bValue2 && bValue3 && bValue4);
// scenario 2
valid = valid || (bValue1 && bValue2 && bValue3 && !bValue4);
// scenario 3
valid = valid || (bValue1 && !bValue2 && !bValue3 && !bValue4);
add a comment |
up vote
-2
down vote
A simple approach is finding the answer that you think are acceptable.
Yes = (boolean1 && boolean2 && boolean3 && boolean4) + + ...
Now if possible simplify the equation using boolean algebra.
like in this case, acceptable1 and 2 combine to (boolean1 && boolean2 && boolean3)
.
Hence the final answer is:
(boolean1 && boolean2 && boolean3) ||
((boolean1 && !boolean2 && !boolean3 && !boolean4)
add a comment |
up vote
-3
down vote
use bit field:
unoin {
struct {
bool b1: 1;
bool b2: 1;
bool b3: 1;
bool b4: 1;
} b;
int i;
} u;
// set:
u.b.b1=true;
...
// test
if (u.i == 0x0f) {...}
if (u.i == 0x0e) {...}
if (u.i == 0x08) {...}
PS:
That's a big pity to CPPers'. But, UB is not my worry, check it at http://coliru.stacked-crooked.com/a/2b556abfc28574a1.
2
This causes UB due to accessing an inactive union field.
– HolyBlackCat
2 days ago
Formally it's UB in C++, you can't set one member of union and read from another. Technically it might be better to implement templated getterssetters for bits of integral value.
– Swift - Friday Pie
2 days ago
I think the behavior would shift to Implementation-Defined if one were to convert the union's address to anunsigned char*
, though I think simply using something like((((flag4 <<1) | flag3) << 1) | flag2) << 1) | flag1
would probably be more efficient.
– supercat
2 days ago
add a comment |
28 Answers
28
active
oldest
votes
28 Answers
28
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
150
down vote
accepted
I would aim for readability: you have just 3 scenario, deal with them with 3 separate ifs:
bool valid = false;
if (bValue1 && bValue2 && bValue3 && bValue4)
valid = true; //scenario 1
else if (bValue1 && bValue2 && bValue3 && !bValue4)
valid = true; //scenario 2
else if (bValue1 && !bValue2 && !bValue3 && !bValue4)
valid = true; //scenario 3
Easy to read and debug, IMHO. Also, you can assign a variable whichScenario
while proceeding with the if
.
With just 3 scenarios, I would not go with something such "if the first 3 values are true I can avoid check the forth value": it's going to make your code harder to read and maintain.
Not an elegant solution maybe, but in this case is ok: easy and readable.
If your logic gets more complicated, consider using something more to store different available scenarios (as Zladeck is suggesting).
4
Damn, simplicity is a virtue. I think this is the best answer, far better than mine or any other obfuscating technique! Bravo!
– gsamaras
Dec 3 at 10:34
1
sure @hessamhedieh, it's ok only for a small number of available scenario. as I said, if things get more complicated, better look for something else
– Gian Paolo
Dec 3 at 10:49
2
This can be simplified further by stacking all conditions into the initializer forvalid
and separating them with||
, rather than mutatingvalid
within separate statement blocks. I can't put an example in the comment but you can vertically align the||
operators along the left to make this very clear; the individual conditions are already parenthesized as much as they need to be (forif
) so you don't need to add any characters to the expressions beyond what is already there.
– Leushenko
Dec 3 at 11:13
1
@Leushenko, I think that mixing parenthesis, && and || conditions is quite error prone (someone in a different answer said there was an error in parenthesis in the code in OP, maybe it has been corrected). Proper alignment can help, sure. But what is the advantage? more readable? easier to maintain? I don't think so. Just my opinion, of course. An be sure, I really hate having lot of ifs in code.
– Gian Paolo
Dec 3 at 12:43
3
I'd've wrapped it in aif($bValue1)
as that always has to be true, technically allowing some minor performance improvement (though we're talking about negligable amounts here).
– Martijn
Dec 3 at 14:36
|
show 13 more comments
up vote
150
down vote
accepted
I would aim for readability: you have just 3 scenario, deal with them with 3 separate ifs:
bool valid = false;
if (bValue1 && bValue2 && bValue3 && bValue4)
valid = true; //scenario 1
else if (bValue1 && bValue2 && bValue3 && !bValue4)
valid = true; //scenario 2
else if (bValue1 && !bValue2 && !bValue3 && !bValue4)
valid = true; //scenario 3
Easy to read and debug, IMHO. Also, you can assign a variable whichScenario
while proceeding with the if
.
With just 3 scenarios, I would not go with something such "if the first 3 values are true I can avoid check the forth value": it's going to make your code harder to read and maintain.
Not an elegant solution maybe, but in this case is ok: easy and readable.
If your logic gets more complicated, consider using something more to store different available scenarios (as Zladeck is suggesting).
4
Damn, simplicity is a virtue. I think this is the best answer, far better than mine or any other obfuscating technique! Bravo!
– gsamaras
Dec 3 at 10:34
1
sure @hessamhedieh, it's ok only for a small number of available scenario. as I said, if things get more complicated, better look for something else
– Gian Paolo
Dec 3 at 10:49
2
This can be simplified further by stacking all conditions into the initializer forvalid
and separating them with||
, rather than mutatingvalid
within separate statement blocks. I can't put an example in the comment but you can vertically align the||
operators along the left to make this very clear; the individual conditions are already parenthesized as much as they need to be (forif
) so you don't need to add any characters to the expressions beyond what is already there.
– Leushenko
Dec 3 at 11:13
1
@Leushenko, I think that mixing parenthesis, && and || conditions is quite error prone (someone in a different answer said there was an error in parenthesis in the code in OP, maybe it has been corrected). Proper alignment can help, sure. But what is the advantage? more readable? easier to maintain? I don't think so. Just my opinion, of course. An be sure, I really hate having lot of ifs in code.
– Gian Paolo
Dec 3 at 12:43
3
I'd've wrapped it in aif($bValue1)
as that always has to be true, technically allowing some minor performance improvement (though we're talking about negligable amounts here).
– Martijn
Dec 3 at 14:36
|
show 13 more comments
up vote
150
down vote
accepted
up vote
150
down vote
accepted
I would aim for readability: you have just 3 scenario, deal with them with 3 separate ifs:
bool valid = false;
if (bValue1 && bValue2 && bValue3 && bValue4)
valid = true; //scenario 1
else if (bValue1 && bValue2 && bValue3 && !bValue4)
valid = true; //scenario 2
else if (bValue1 && !bValue2 && !bValue3 && !bValue4)
valid = true; //scenario 3
Easy to read and debug, IMHO. Also, you can assign a variable whichScenario
while proceeding with the if
.
With just 3 scenarios, I would not go with something such "if the first 3 values are true I can avoid check the forth value": it's going to make your code harder to read and maintain.
Not an elegant solution maybe, but in this case is ok: easy and readable.
If your logic gets more complicated, consider using something more to store different available scenarios (as Zladeck is suggesting).
I would aim for readability: you have just 3 scenario, deal with them with 3 separate ifs:
bool valid = false;
if (bValue1 && bValue2 && bValue3 && bValue4)
valid = true; //scenario 1
else if (bValue1 && bValue2 && bValue3 && !bValue4)
valid = true; //scenario 2
else if (bValue1 && !bValue2 && !bValue3 && !bValue4)
valid = true; //scenario 3
Easy to read and debug, IMHO. Also, you can assign a variable whichScenario
while proceeding with the if
.
With just 3 scenarios, I would not go with something such "if the first 3 values are true I can avoid check the forth value": it's going to make your code harder to read and maintain.
Not an elegant solution maybe, but in this case is ok: easy and readable.
If your logic gets more complicated, consider using something more to store different available scenarios (as Zladeck is suggesting).
edited Dec 3 at 14:44
Andrew Truckle
5,16032145
5,16032145
answered Dec 3 at 10:29
Gian Paolo
2,8492925
2,8492925
4
Damn, simplicity is a virtue. I think this is the best answer, far better than mine or any other obfuscating technique! Bravo!
– gsamaras
Dec 3 at 10:34
1
sure @hessamhedieh, it's ok only for a small number of available scenario. as I said, if things get more complicated, better look for something else
– Gian Paolo
Dec 3 at 10:49
2
This can be simplified further by stacking all conditions into the initializer forvalid
and separating them with||
, rather than mutatingvalid
within separate statement blocks. I can't put an example in the comment but you can vertically align the||
operators along the left to make this very clear; the individual conditions are already parenthesized as much as they need to be (forif
) so you don't need to add any characters to the expressions beyond what is already there.
– Leushenko
Dec 3 at 11:13
1
@Leushenko, I think that mixing parenthesis, && and || conditions is quite error prone (someone in a different answer said there was an error in parenthesis in the code in OP, maybe it has been corrected). Proper alignment can help, sure. But what is the advantage? more readable? easier to maintain? I don't think so. Just my opinion, of course. An be sure, I really hate having lot of ifs in code.
– Gian Paolo
Dec 3 at 12:43
3
I'd've wrapped it in aif($bValue1)
as that always has to be true, technically allowing some minor performance improvement (though we're talking about negligable amounts here).
– Martijn
Dec 3 at 14:36
|
show 13 more comments
4
Damn, simplicity is a virtue. I think this is the best answer, far better than mine or any other obfuscating technique! Bravo!
– gsamaras
Dec 3 at 10:34
1
sure @hessamhedieh, it's ok only for a small number of available scenario. as I said, if things get more complicated, better look for something else
– Gian Paolo
Dec 3 at 10:49
2
This can be simplified further by stacking all conditions into the initializer forvalid
and separating them with||
, rather than mutatingvalid
within separate statement blocks. I can't put an example in the comment but you can vertically align the||
operators along the left to make this very clear; the individual conditions are already parenthesized as much as they need to be (forif
) so you don't need to add any characters to the expressions beyond what is already there.
– Leushenko
Dec 3 at 11:13
1
@Leushenko, I think that mixing parenthesis, && and || conditions is quite error prone (someone in a different answer said there was an error in parenthesis in the code in OP, maybe it has been corrected). Proper alignment can help, sure. But what is the advantage? more readable? easier to maintain? I don't think so. Just my opinion, of course. An be sure, I really hate having lot of ifs in code.
– Gian Paolo
Dec 3 at 12:43
3
I'd've wrapped it in aif($bValue1)
as that always has to be true, technically allowing some minor performance improvement (though we're talking about negligable amounts here).
– Martijn
Dec 3 at 14:36
4
4
Damn, simplicity is a virtue. I think this is the best answer, far better than mine or any other obfuscating technique! Bravo!
– gsamaras
Dec 3 at 10:34
Damn, simplicity is a virtue. I think this is the best answer, far better than mine or any other obfuscating technique! Bravo!
– gsamaras
Dec 3 at 10:34
1
1
sure @hessamhedieh, it's ok only for a small number of available scenario. as I said, if things get more complicated, better look for something else
– Gian Paolo
Dec 3 at 10:49
sure @hessamhedieh, it's ok only for a small number of available scenario. as I said, if things get more complicated, better look for something else
– Gian Paolo
Dec 3 at 10:49
2
2
This can be simplified further by stacking all conditions into the initializer for
valid
and separating them with ||
, rather than mutating valid
within separate statement blocks. I can't put an example in the comment but you can vertically align the ||
operators along the left to make this very clear; the individual conditions are already parenthesized as much as they need to be (for if
) so you don't need to add any characters to the expressions beyond what is already there.– Leushenko
Dec 3 at 11:13
This can be simplified further by stacking all conditions into the initializer for
valid
and separating them with ||
, rather than mutating valid
within separate statement blocks. I can't put an example in the comment but you can vertically align the ||
operators along the left to make this very clear; the individual conditions are already parenthesized as much as they need to be (for if
) so you don't need to add any characters to the expressions beyond what is already there.– Leushenko
Dec 3 at 11:13
1
1
@Leushenko, I think that mixing parenthesis, && and || conditions is quite error prone (someone in a different answer said there was an error in parenthesis in the code in OP, maybe it has been corrected). Proper alignment can help, sure. But what is the advantage? more readable? easier to maintain? I don't think so. Just my opinion, of course. An be sure, I really hate having lot of ifs in code.
– Gian Paolo
Dec 3 at 12:43
@Leushenko, I think that mixing parenthesis, && and || conditions is quite error prone (someone in a different answer said there was an error in parenthesis in the code in OP, maybe it has been corrected). Proper alignment can help, sure. But what is the advantage? more readable? easier to maintain? I don't think so. Just my opinion, of course. An be sure, I really hate having lot of ifs in code.
– Gian Paolo
Dec 3 at 12:43
3
3
I'd've wrapped it in a
if($bValue1)
as that always has to be true, technically allowing some minor performance improvement (though we're talking about negligable amounts here).– Martijn
Dec 3 at 14:36
I'd've wrapped it in a
if($bValue1)
as that always has to be true, technically allowing some minor performance improvement (though we're talking about negligable amounts here).– Martijn
Dec 3 at 14:36
|
show 13 more comments
up vote
80
down vote
We can use a Karnaugh map and reduce your scenarios to a logical equation.
I have used the Online Karnaugh map solver with circuit for 4 variables.
This yields:
Changing A, B, C, D
to bValue1, bValue2, bValue3, bValue4
, this is nothing but:
bValue1 && bValue2 && bValue3 || bValue1 && !bValue2 && !bValue3 && !bValue4
So your if
statement becomes:
if(!(bValue1 && bValue2 && bValue3 || bValue1 && !bValue2 && !bValue3 && !bValue4))
{
// There is some error
}
- Karnaugh Maps are particularly useful when you have many variables and many conditions which should evaluate
true
. - After reducing the
true
scenarios to a logical equation, adding relevant comments indicating thetrue
scenarios is good practice.
82
Though technically correct, this code requires a lot of comments in order to be edited by another developer few months later.
– Zdeslav Vojkovic
Dec 3 at 11:00
15
@ZdeslavVojkovic: I would just add a comment with the equation.//!(ABC + AB'C'D') (By K-Map logic)
. That would be a good time for the developer to learn K-Maps if he doesn't already know them.
– P.W
Dec 3 at 11:05
9
I agree with that, but IMO the problem is that it doesn't map clearly to the problem domain, i.e. how each condition maps to specific scenario which makes it hard to change/extend. What happens when there areE
andF
conditions and 4 new scenarios? How long it takes to update thisif
statement correctly? How does code review check if it is ok or not? The problem is not with the technical side but with "business" side.
– Zdeslav Vojkovic
Dec 3 at 11:09
7
I think you can factor outA
:ABC + AB'C'D' = A(BC + B'C'D')
(this can be even factored toA(B ^ C)'(C + D')
though I'd be careful with calling this 'simplification').
– Maciej Piechotka
Dec 3 at 11:31
18
@P.W That comment seems about as understandable as the code, and is thus a bit pointless. A better comment would explain how you actually came up with that equation, i.e. that the statement should trigger for TTTT, TTTF and TFFF. At that point you might as well just write those three conditions in the code instead and not need an explanation at all.
– Dukeling
Dec 3 at 14:21
|
show 10 more comments
up vote
80
down vote
We can use a Karnaugh map and reduce your scenarios to a logical equation.
I have used the Online Karnaugh map solver with circuit for 4 variables.
This yields:
Changing A, B, C, D
to bValue1, bValue2, bValue3, bValue4
, this is nothing but:
bValue1 && bValue2 && bValue3 || bValue1 && !bValue2 && !bValue3 && !bValue4
So your if
statement becomes:
if(!(bValue1 && bValue2 && bValue3 || bValue1 && !bValue2 && !bValue3 && !bValue4))
{
// There is some error
}
- Karnaugh Maps are particularly useful when you have many variables and many conditions which should evaluate
true
. - After reducing the
true
scenarios to a logical equation, adding relevant comments indicating thetrue
scenarios is good practice.
82
Though technically correct, this code requires a lot of comments in order to be edited by another developer few months later.
– Zdeslav Vojkovic
Dec 3 at 11:00
15
@ZdeslavVojkovic: I would just add a comment with the equation.//!(ABC + AB'C'D') (By K-Map logic)
. That would be a good time for the developer to learn K-Maps if he doesn't already know them.
– P.W
Dec 3 at 11:05
9
I agree with that, but IMO the problem is that it doesn't map clearly to the problem domain, i.e. how each condition maps to specific scenario which makes it hard to change/extend. What happens when there areE
andF
conditions and 4 new scenarios? How long it takes to update thisif
statement correctly? How does code review check if it is ok or not? The problem is not with the technical side but with "business" side.
– Zdeslav Vojkovic
Dec 3 at 11:09
7
I think you can factor outA
:ABC + AB'C'D' = A(BC + B'C'D')
(this can be even factored toA(B ^ C)'(C + D')
though I'd be careful with calling this 'simplification').
– Maciej Piechotka
Dec 3 at 11:31
18
@P.W That comment seems about as understandable as the code, and is thus a bit pointless. A better comment would explain how you actually came up with that equation, i.e. that the statement should trigger for TTTT, TTTF and TFFF. At that point you might as well just write those three conditions in the code instead and not need an explanation at all.
– Dukeling
Dec 3 at 14:21
|
show 10 more comments
up vote
80
down vote
up vote
80
down vote
We can use a Karnaugh map and reduce your scenarios to a logical equation.
I have used the Online Karnaugh map solver with circuit for 4 variables.
This yields:
Changing A, B, C, D
to bValue1, bValue2, bValue3, bValue4
, this is nothing but:
bValue1 && bValue2 && bValue3 || bValue1 && !bValue2 && !bValue3 && !bValue4
So your if
statement becomes:
if(!(bValue1 && bValue2 && bValue3 || bValue1 && !bValue2 && !bValue3 && !bValue4))
{
// There is some error
}
- Karnaugh Maps are particularly useful when you have many variables and many conditions which should evaluate
true
. - After reducing the
true
scenarios to a logical equation, adding relevant comments indicating thetrue
scenarios is good practice.
We can use a Karnaugh map and reduce your scenarios to a logical equation.
I have used the Online Karnaugh map solver with circuit for 4 variables.
This yields:
Changing A, B, C, D
to bValue1, bValue2, bValue3, bValue4
, this is nothing but:
bValue1 && bValue2 && bValue3 || bValue1 && !bValue2 && !bValue3 && !bValue4
So your if
statement becomes:
if(!(bValue1 && bValue2 && bValue3 || bValue1 && !bValue2 && !bValue3 && !bValue4))
{
// There is some error
}
- Karnaugh Maps are particularly useful when you have many variables and many conditions which should evaluate
true
. - After reducing the
true
scenarios to a logical equation, adding relevant comments indicating thetrue
scenarios is good practice.
edited 2 days ago
answered Dec 3 at 10:38
P.W
9,5412742
9,5412742
82
Though technically correct, this code requires a lot of comments in order to be edited by another developer few months later.
– Zdeslav Vojkovic
Dec 3 at 11:00
15
@ZdeslavVojkovic: I would just add a comment with the equation.//!(ABC + AB'C'D') (By K-Map logic)
. That would be a good time for the developer to learn K-Maps if he doesn't already know them.
– P.W
Dec 3 at 11:05
9
I agree with that, but IMO the problem is that it doesn't map clearly to the problem domain, i.e. how each condition maps to specific scenario which makes it hard to change/extend. What happens when there areE
andF
conditions and 4 new scenarios? How long it takes to update thisif
statement correctly? How does code review check if it is ok or not? The problem is not with the technical side but with "business" side.
– Zdeslav Vojkovic
Dec 3 at 11:09
7
I think you can factor outA
:ABC + AB'C'D' = A(BC + B'C'D')
(this can be even factored toA(B ^ C)'(C + D')
though I'd be careful with calling this 'simplification').
– Maciej Piechotka
Dec 3 at 11:31
18
@P.W That comment seems about as understandable as the code, and is thus a bit pointless. A better comment would explain how you actually came up with that equation, i.e. that the statement should trigger for TTTT, TTTF and TFFF. At that point you might as well just write those three conditions in the code instead and not need an explanation at all.
– Dukeling
Dec 3 at 14:21
|
show 10 more comments
82
Though technically correct, this code requires a lot of comments in order to be edited by another developer few months later.
– Zdeslav Vojkovic
Dec 3 at 11:00
15
@ZdeslavVojkovic: I would just add a comment with the equation.//!(ABC + AB'C'D') (By K-Map logic)
. That would be a good time for the developer to learn K-Maps if he doesn't already know them.
– P.W
Dec 3 at 11:05
9
I agree with that, but IMO the problem is that it doesn't map clearly to the problem domain, i.e. how each condition maps to specific scenario which makes it hard to change/extend. What happens when there areE
andF
conditions and 4 new scenarios? How long it takes to update thisif
statement correctly? How does code review check if it is ok or not? The problem is not with the technical side but with "business" side.
– Zdeslav Vojkovic
Dec 3 at 11:09
7
I think you can factor outA
:ABC + AB'C'D' = A(BC + B'C'D')
(this can be even factored toA(B ^ C)'(C + D')
though I'd be careful with calling this 'simplification').
– Maciej Piechotka
Dec 3 at 11:31
18
@P.W That comment seems about as understandable as the code, and is thus a bit pointless. A better comment would explain how you actually came up with that equation, i.e. that the statement should trigger for TTTT, TTTF and TFFF. At that point you might as well just write those three conditions in the code instead and not need an explanation at all.
– Dukeling
Dec 3 at 14:21
82
82
Though technically correct, this code requires a lot of comments in order to be edited by another developer few months later.
– Zdeslav Vojkovic
Dec 3 at 11:00
Though technically correct, this code requires a lot of comments in order to be edited by another developer few months later.
– Zdeslav Vojkovic
Dec 3 at 11:00
15
15
@ZdeslavVojkovic: I would just add a comment with the equation.
//!(ABC + AB'C'D') (By K-Map logic)
. That would be a good time for the developer to learn K-Maps if he doesn't already know them.– P.W
Dec 3 at 11:05
@ZdeslavVojkovic: I would just add a comment with the equation.
//!(ABC + AB'C'D') (By K-Map logic)
. That would be a good time for the developer to learn K-Maps if he doesn't already know them.– P.W
Dec 3 at 11:05
9
9
I agree with that, but IMO the problem is that it doesn't map clearly to the problem domain, i.e. how each condition maps to specific scenario which makes it hard to change/extend. What happens when there are
E
and F
conditions and 4 new scenarios? How long it takes to update this if
statement correctly? How does code review check if it is ok or not? The problem is not with the technical side but with "business" side.– Zdeslav Vojkovic
Dec 3 at 11:09
I agree with that, but IMO the problem is that it doesn't map clearly to the problem domain, i.e. how each condition maps to specific scenario which makes it hard to change/extend. What happens when there are
E
and F
conditions and 4 new scenarios? How long it takes to update this if
statement correctly? How does code review check if it is ok or not? The problem is not with the technical side but with "business" side.– Zdeslav Vojkovic
Dec 3 at 11:09
7
7
I think you can factor out
A
: ABC + AB'C'D' = A(BC + B'C'D')
(this can be even factored to A(B ^ C)'(C + D')
though I'd be careful with calling this 'simplification').– Maciej Piechotka
Dec 3 at 11:31
I think you can factor out
A
: ABC + AB'C'D' = A(BC + B'C'D')
(this can be even factored to A(B ^ C)'(C + D')
though I'd be careful with calling this 'simplification').– Maciej Piechotka
Dec 3 at 11:31
18
18
@P.W That comment seems about as understandable as the code, and is thus a bit pointless. A better comment would explain how you actually came up with that equation, i.e. that the statement should trigger for TTTT, TTTF and TFFF. At that point you might as well just write those three conditions in the code instead and not need an explanation at all.
– Dukeling
Dec 3 at 14:21
@P.W That comment seems about as understandable as the code, and is thus a bit pointless. A better comment would explain how you actually came up with that equation, i.e. that the statement should trigger for TTTT, TTTF and TFFF. At that point you might as well just write those three conditions in the code instead and not need an explanation at all.
– Dukeling
Dec 3 at 14:21
|
show 10 more comments
up vote
72
down vote
I would aim for simplicity and readability.
bool scenario1 = bValue1 && bValue2 && bValue3 && bValue4;
bool scenario2 = bValue1 && bValue2 && bValue3 && !bValue4;
bool scenario3 = bValue1 && !bValue2 && !bValue3 && !bValue4;
if (scenario1 || scenario2 || scenario3) {
// Do whatever.
}
Make sure to replace the names of the scenarios as well as the names of the flags with something descriptive. If it makes sense for your specific problem, you could consider this alternative:
bool scenario1or2 = bValue1 && bValue2 && bValue3;
bool scenario3 = bValue1 && !bValue2 && !bValue3 && !bValue4;
if (scenario1or2 || scenario3) {
// Do whatever.
}
What's important here is not predicate logic or Karnaugh maps. It's describing your domain and clearly expressing your intent. The key here is to give all inputs and intermediary variables good names. If you can't find good variable names, it may be a sign that you are describing the problem in the wrong way.
3
+1 I am surprised there are 0 upvotes here. The solution is short, self-documenting (no comments needed), and easy to modify with little chance of introducing bugs. A clear favourite.
– RedFilter
2 days ago
2
Thanks for this. In my solution that I provided as an answer I also took onboard what you said. The only different being that I moved the scenarios into methods.
– Andrew Truckle
yesterday
+1 This is what I would have done as well. Just like @RedFilter points out, and in contrast to the accepted answer, this is self-documenting. Giving the scenarios their own names in a separate step is much more readable.
– Andreas
yesterday
add a comment |
up vote
72
down vote
I would aim for simplicity and readability.
bool scenario1 = bValue1 && bValue2 && bValue3 && bValue4;
bool scenario2 = bValue1 && bValue2 && bValue3 && !bValue4;
bool scenario3 = bValue1 && !bValue2 && !bValue3 && !bValue4;
if (scenario1 || scenario2 || scenario3) {
// Do whatever.
}
Make sure to replace the names of the scenarios as well as the names of the flags with something descriptive. If it makes sense for your specific problem, you could consider this alternative:
bool scenario1or2 = bValue1 && bValue2 && bValue3;
bool scenario3 = bValue1 && !bValue2 && !bValue3 && !bValue4;
if (scenario1or2 || scenario3) {
// Do whatever.
}
What's important here is not predicate logic or Karnaugh maps. It's describing your domain and clearly expressing your intent. The key here is to give all inputs and intermediary variables good names. If you can't find good variable names, it may be a sign that you are describing the problem in the wrong way.
3
+1 I am surprised there are 0 upvotes here. The solution is short, self-documenting (no comments needed), and easy to modify with little chance of introducing bugs. A clear favourite.
– RedFilter
2 days ago
2
Thanks for this. In my solution that I provided as an answer I also took onboard what you said. The only different being that I moved the scenarios into methods.
– Andrew Truckle
yesterday
+1 This is what I would have done as well. Just like @RedFilter points out, and in contrast to the accepted answer, this is self-documenting. Giving the scenarios their own names in a separate step is much more readable.
– Andreas
yesterday
add a comment |
up vote
72
down vote
up vote
72
down vote
I would aim for simplicity and readability.
bool scenario1 = bValue1 && bValue2 && bValue3 && bValue4;
bool scenario2 = bValue1 && bValue2 && bValue3 && !bValue4;
bool scenario3 = bValue1 && !bValue2 && !bValue3 && !bValue4;
if (scenario1 || scenario2 || scenario3) {
// Do whatever.
}
Make sure to replace the names of the scenarios as well as the names of the flags with something descriptive. If it makes sense for your specific problem, you could consider this alternative:
bool scenario1or2 = bValue1 && bValue2 && bValue3;
bool scenario3 = bValue1 && !bValue2 && !bValue3 && !bValue4;
if (scenario1or2 || scenario3) {
// Do whatever.
}
What's important here is not predicate logic or Karnaugh maps. It's describing your domain and clearly expressing your intent. The key here is to give all inputs and intermediary variables good names. If you can't find good variable names, it may be a sign that you are describing the problem in the wrong way.
I would aim for simplicity and readability.
bool scenario1 = bValue1 && bValue2 && bValue3 && bValue4;
bool scenario2 = bValue1 && bValue2 && bValue3 && !bValue4;
bool scenario3 = bValue1 && !bValue2 && !bValue3 && !bValue4;
if (scenario1 || scenario2 || scenario3) {
// Do whatever.
}
Make sure to replace the names of the scenarios as well as the names of the flags with something descriptive. If it makes sense for your specific problem, you could consider this alternative:
bool scenario1or2 = bValue1 && bValue2 && bValue3;
bool scenario3 = bValue1 && !bValue2 && !bValue3 && !bValue4;
if (scenario1or2 || scenario3) {
// Do whatever.
}
What's important here is not predicate logic or Karnaugh maps. It's describing your domain and clearly expressing your intent. The key here is to give all inputs and intermediary variables good names. If you can't find good variable names, it may be a sign that you are describing the problem in the wrong way.
edited yesterday
answered 2 days ago
Anders
5,08653052
5,08653052
3
+1 I am surprised there are 0 upvotes here. The solution is short, self-documenting (no comments needed), and easy to modify with little chance of introducing bugs. A clear favourite.
– RedFilter
2 days ago
2
Thanks for this. In my solution that I provided as an answer I also took onboard what you said. The only different being that I moved the scenarios into methods.
– Andrew Truckle
yesterday
+1 This is what I would have done as well. Just like @RedFilter points out, and in contrast to the accepted answer, this is self-documenting. Giving the scenarios their own names in a separate step is much more readable.
– Andreas
yesterday
add a comment |
3
+1 I am surprised there are 0 upvotes here. The solution is short, self-documenting (no comments needed), and easy to modify with little chance of introducing bugs. A clear favourite.
– RedFilter
2 days ago
2
Thanks for this. In my solution that I provided as an answer I also took onboard what you said. The only different being that I moved the scenarios into methods.
– Andrew Truckle
yesterday
+1 This is what I would have done as well. Just like @RedFilter points out, and in contrast to the accepted answer, this is self-documenting. Giving the scenarios their own names in a separate step is much more readable.
– Andreas
yesterday
3
3
+1 I am surprised there are 0 upvotes here. The solution is short, self-documenting (no comments needed), and easy to modify with little chance of introducing bugs. A clear favourite.
– RedFilter
2 days ago
+1 I am surprised there are 0 upvotes here. The solution is short, self-documenting (no comments needed), and easy to modify with little chance of introducing bugs. A clear favourite.
– RedFilter
2 days ago
2
2
Thanks for this. In my solution that I provided as an answer I also took onboard what you said. The only different being that I moved the scenarios into methods.
– Andrew Truckle
yesterday
Thanks for this. In my solution that I provided as an answer I also took onboard what you said. The only different being that I moved the scenarios into methods.
– Andrew Truckle
yesterday
+1 This is what I would have done as well. Just like @RedFilter points out, and in contrast to the accepted answer, this is self-documenting. Giving the scenarios their own names in a separate step is much more readable.
– Andreas
yesterday
+1 This is what I would have done as well. Just like @RedFilter points out, and in contrast to the accepted answer, this is self-documenting. Giving the scenarios their own names in a separate step is much more readable.
– Andreas
yesterday
add a comment |
up vote
45
down vote
The real question here is: what happens when another developer (or even author) must change this code few months later.
I would suggest modelling this as bit flags:
const int SCENARIO_1 = 0x0F; // 0b1111 if using c++14
const int SCENARIO_2 = 0x0E; // 0b1110
const int SCENARIO_3 = 0x08; // 0b1000
bool bValue1 = true;
bool bValue2 = false;
bool bValue3 = false;
bool bValue4 = false;
// boolean -> int conversion is covered by standard and produces 0/1
int scenario = bValue1 << 3 | bValue2 << 2 | bValue3 << 1 | bValue4;
bool match = scenario == SCENARIO_1 || scenario == SCENARIO_2 || scenario == SCENARIO_3;
std::cout << (match ? "ok" : "error");
If there are many more scenarios or more flags, a table approach is more readable and extensible than using flags. Supporting a new scenario requires just another row in the table.
int scenarios[3][4] = {
{true, true, true, true},
{true, true, true, false},
{true, false, false, false},
};
int main()
{
bool bValue1 = true;
bool bValue2 = false;
bool bValue3 = true;
bool bValue4 = true;
bool match = false;
// depending on compiler, prefer std::size()/_countof instead of magic value of 4
for (int i = 0; i < 4 && !match; ++i) {
auto current = scenarios[i];
match = bValue1 == current[0] &&
bValue2 == current[1] &&
bValue3 == current[2] &&
bValue4 == current[3];
}
std::cout << (match ? "ok" : "error");
}
3
Not the most maintainable but definitely simplifies the if condition. So leaving a few comments around the bitwise operations will be an absolute necessity here imo.
– Adam Zahran
Dec 3 at 10:35
5
IMO, table is the best approach as it scales better with additional scenarios and flags.
– Zdeslav Vojkovic
Dec 3 at 10:44
I like your first solution, easy to read and open to modification. I would make 2 improvements: 1: assign values to scenarioX with an explicit indication of boolean values used, e.g.SCENARIO_2 = true << 3 | true << 2 | true << 1 | false;
2: avoid SCENARIO_X variables and then store all available scenarios in a<std::set<int>
. Adding a scenario is going to be just something asmySet.insert( true << 3 | false << 2 | true << 1 | false;
maybe a little overkill for just 3 scenario, OP accepted the quick, dirty and easy solution I suggested in my answer.
– Gian Paolo
Dec 3 at 12:52
4
If you're using C++14 or higher, I'd suggest instead using binary literals for the first solution - 0b1111, 0b1110 and 0b1000 is much clearer. You can probably also simplify this a bit using the standard library (std::find
?).
– Dukeling
Dec 3 at 14:25
2
I find that binary literals here would be a minimal requirement to make the first code clean. In its current form it’s completely cryptic. Descriptive identifiers might help but I’m not even sure about that. In fact, the bit operations to produce thescenario
value strike me as unnecessarily error-prone.
– Konrad Rudolph
Dec 3 at 22:25
add a comment |
up vote
45
down vote
The real question here is: what happens when another developer (or even author) must change this code few months later.
I would suggest modelling this as bit flags:
const int SCENARIO_1 = 0x0F; // 0b1111 if using c++14
const int SCENARIO_2 = 0x0E; // 0b1110
const int SCENARIO_3 = 0x08; // 0b1000
bool bValue1 = true;
bool bValue2 = false;
bool bValue3 = false;
bool bValue4 = false;
// boolean -> int conversion is covered by standard and produces 0/1
int scenario = bValue1 << 3 | bValue2 << 2 | bValue3 << 1 | bValue4;
bool match = scenario == SCENARIO_1 || scenario == SCENARIO_2 || scenario == SCENARIO_3;
std::cout << (match ? "ok" : "error");
If there are many more scenarios or more flags, a table approach is more readable and extensible than using flags. Supporting a new scenario requires just another row in the table.
int scenarios[3][4] = {
{true, true, true, true},
{true, true, true, false},
{true, false, false, false},
};
int main()
{
bool bValue1 = true;
bool bValue2 = false;
bool bValue3 = true;
bool bValue4 = true;
bool match = false;
// depending on compiler, prefer std::size()/_countof instead of magic value of 4
for (int i = 0; i < 4 && !match; ++i) {
auto current = scenarios[i];
match = bValue1 == current[0] &&
bValue2 == current[1] &&
bValue3 == current[2] &&
bValue4 == current[3];
}
std::cout << (match ? "ok" : "error");
}
3
Not the most maintainable but definitely simplifies the if condition. So leaving a few comments around the bitwise operations will be an absolute necessity here imo.
– Adam Zahran
Dec 3 at 10:35
5
IMO, table is the best approach as it scales better with additional scenarios and flags.
– Zdeslav Vojkovic
Dec 3 at 10:44
I like your first solution, easy to read and open to modification. I would make 2 improvements: 1: assign values to scenarioX with an explicit indication of boolean values used, e.g.SCENARIO_2 = true << 3 | true << 2 | true << 1 | false;
2: avoid SCENARIO_X variables and then store all available scenarios in a<std::set<int>
. Adding a scenario is going to be just something asmySet.insert( true << 3 | false << 2 | true << 1 | false;
maybe a little overkill for just 3 scenario, OP accepted the quick, dirty and easy solution I suggested in my answer.
– Gian Paolo
Dec 3 at 12:52
4
If you're using C++14 or higher, I'd suggest instead using binary literals for the first solution - 0b1111, 0b1110 and 0b1000 is much clearer. You can probably also simplify this a bit using the standard library (std::find
?).
– Dukeling
Dec 3 at 14:25
2
I find that binary literals here would be a minimal requirement to make the first code clean. In its current form it’s completely cryptic. Descriptive identifiers might help but I’m not even sure about that. In fact, the bit operations to produce thescenario
value strike me as unnecessarily error-prone.
– Konrad Rudolph
Dec 3 at 22:25
add a comment |
up vote
45
down vote
up vote
45
down vote
The real question here is: what happens when another developer (or even author) must change this code few months later.
I would suggest modelling this as bit flags:
const int SCENARIO_1 = 0x0F; // 0b1111 if using c++14
const int SCENARIO_2 = 0x0E; // 0b1110
const int SCENARIO_3 = 0x08; // 0b1000
bool bValue1 = true;
bool bValue2 = false;
bool bValue3 = false;
bool bValue4 = false;
// boolean -> int conversion is covered by standard and produces 0/1
int scenario = bValue1 << 3 | bValue2 << 2 | bValue3 << 1 | bValue4;
bool match = scenario == SCENARIO_1 || scenario == SCENARIO_2 || scenario == SCENARIO_3;
std::cout << (match ? "ok" : "error");
If there are many more scenarios or more flags, a table approach is more readable and extensible than using flags. Supporting a new scenario requires just another row in the table.
int scenarios[3][4] = {
{true, true, true, true},
{true, true, true, false},
{true, false, false, false},
};
int main()
{
bool bValue1 = true;
bool bValue2 = false;
bool bValue3 = true;
bool bValue4 = true;
bool match = false;
// depending on compiler, prefer std::size()/_countof instead of magic value of 4
for (int i = 0; i < 4 && !match; ++i) {
auto current = scenarios[i];
match = bValue1 == current[0] &&
bValue2 == current[1] &&
bValue3 == current[2] &&
bValue4 == current[3];
}
std::cout << (match ? "ok" : "error");
}
The real question here is: what happens when another developer (or even author) must change this code few months later.
I would suggest modelling this as bit flags:
const int SCENARIO_1 = 0x0F; // 0b1111 if using c++14
const int SCENARIO_2 = 0x0E; // 0b1110
const int SCENARIO_3 = 0x08; // 0b1000
bool bValue1 = true;
bool bValue2 = false;
bool bValue3 = false;
bool bValue4 = false;
// boolean -> int conversion is covered by standard and produces 0/1
int scenario = bValue1 << 3 | bValue2 << 2 | bValue3 << 1 | bValue4;
bool match = scenario == SCENARIO_1 || scenario == SCENARIO_2 || scenario == SCENARIO_3;
std::cout << (match ? "ok" : "error");
If there are many more scenarios or more flags, a table approach is more readable and extensible than using flags. Supporting a new scenario requires just another row in the table.
int scenarios[3][4] = {
{true, true, true, true},
{true, true, true, false},
{true, false, false, false},
};
int main()
{
bool bValue1 = true;
bool bValue2 = false;
bool bValue3 = true;
bool bValue4 = true;
bool match = false;
// depending on compiler, prefer std::size()/_countof instead of magic value of 4
for (int i = 0; i < 4 && !match; ++i) {
auto current = scenarios[i];
match = bValue1 == current[0] &&
bValue2 == current[1] &&
bValue3 == current[2] &&
bValue4 == current[3];
}
std::cout << (match ? "ok" : "error");
}
edited yesterday
Andrew Truckle
5,16032145
5,16032145
answered Dec 3 at 10:33
Zdeslav Vojkovic
12.5k1836
12.5k1836
3
Not the most maintainable but definitely simplifies the if condition. So leaving a few comments around the bitwise operations will be an absolute necessity here imo.
– Adam Zahran
Dec 3 at 10:35
5
IMO, table is the best approach as it scales better with additional scenarios and flags.
– Zdeslav Vojkovic
Dec 3 at 10:44
I like your first solution, easy to read and open to modification. I would make 2 improvements: 1: assign values to scenarioX with an explicit indication of boolean values used, e.g.SCENARIO_2 = true << 3 | true << 2 | true << 1 | false;
2: avoid SCENARIO_X variables and then store all available scenarios in a<std::set<int>
. Adding a scenario is going to be just something asmySet.insert( true << 3 | false << 2 | true << 1 | false;
maybe a little overkill for just 3 scenario, OP accepted the quick, dirty and easy solution I suggested in my answer.
– Gian Paolo
Dec 3 at 12:52
4
If you're using C++14 or higher, I'd suggest instead using binary literals for the first solution - 0b1111, 0b1110 and 0b1000 is much clearer. You can probably also simplify this a bit using the standard library (std::find
?).
– Dukeling
Dec 3 at 14:25
2
I find that binary literals here would be a minimal requirement to make the first code clean. In its current form it’s completely cryptic. Descriptive identifiers might help but I’m not even sure about that. In fact, the bit operations to produce thescenario
value strike me as unnecessarily error-prone.
– Konrad Rudolph
Dec 3 at 22:25
add a comment |
3
Not the most maintainable but definitely simplifies the if condition. So leaving a few comments around the bitwise operations will be an absolute necessity here imo.
– Adam Zahran
Dec 3 at 10:35
5
IMO, table is the best approach as it scales better with additional scenarios and flags.
– Zdeslav Vojkovic
Dec 3 at 10:44
I like your first solution, easy to read and open to modification. I would make 2 improvements: 1: assign values to scenarioX with an explicit indication of boolean values used, e.g.SCENARIO_2 = true << 3 | true << 2 | true << 1 | false;
2: avoid SCENARIO_X variables and then store all available scenarios in a<std::set<int>
. Adding a scenario is going to be just something asmySet.insert( true << 3 | false << 2 | true << 1 | false;
maybe a little overkill for just 3 scenario, OP accepted the quick, dirty and easy solution I suggested in my answer.
– Gian Paolo
Dec 3 at 12:52
4
If you're using C++14 or higher, I'd suggest instead using binary literals for the first solution - 0b1111, 0b1110 and 0b1000 is much clearer. You can probably also simplify this a bit using the standard library (std::find
?).
– Dukeling
Dec 3 at 14:25
2
I find that binary literals here would be a minimal requirement to make the first code clean. In its current form it’s completely cryptic. Descriptive identifiers might help but I’m not even sure about that. In fact, the bit operations to produce thescenario
value strike me as unnecessarily error-prone.
– Konrad Rudolph
Dec 3 at 22:25
3
3
Not the most maintainable but definitely simplifies the if condition. So leaving a few comments around the bitwise operations will be an absolute necessity here imo.
– Adam Zahran
Dec 3 at 10:35
Not the most maintainable but definitely simplifies the if condition. So leaving a few comments around the bitwise operations will be an absolute necessity here imo.
– Adam Zahran
Dec 3 at 10:35
5
5
IMO, table is the best approach as it scales better with additional scenarios and flags.
– Zdeslav Vojkovic
Dec 3 at 10:44
IMO, table is the best approach as it scales better with additional scenarios and flags.
– Zdeslav Vojkovic
Dec 3 at 10:44
I like your first solution, easy to read and open to modification. I would make 2 improvements: 1: assign values to scenarioX with an explicit indication of boolean values used, e.g.
SCENARIO_2 = true << 3 | true << 2 | true << 1 | false;
2: avoid SCENARIO_X variables and then store all available scenarios in a <std::set<int>
. Adding a scenario is going to be just something as mySet.insert( true << 3 | false << 2 | true << 1 | false;
maybe a little overkill for just 3 scenario, OP accepted the quick, dirty and easy solution I suggested in my answer.– Gian Paolo
Dec 3 at 12:52
I like your first solution, easy to read and open to modification. I would make 2 improvements: 1: assign values to scenarioX with an explicit indication of boolean values used, e.g.
SCENARIO_2 = true << 3 | true << 2 | true << 1 | false;
2: avoid SCENARIO_X variables and then store all available scenarios in a <std::set<int>
. Adding a scenario is going to be just something as mySet.insert( true << 3 | false << 2 | true << 1 | false;
maybe a little overkill for just 3 scenario, OP accepted the quick, dirty and easy solution I suggested in my answer.– Gian Paolo
Dec 3 at 12:52
4
4
If you're using C++14 or higher, I'd suggest instead using binary literals for the first solution - 0b1111, 0b1110 and 0b1000 is much clearer. You can probably also simplify this a bit using the standard library (
std::find
?).– Dukeling
Dec 3 at 14:25
If you're using C++14 or higher, I'd suggest instead using binary literals for the first solution - 0b1111, 0b1110 and 0b1000 is much clearer. You can probably also simplify this a bit using the standard library (
std::find
?).– Dukeling
Dec 3 at 14:25
2
2
I find that binary literals here would be a minimal requirement to make the first code clean. In its current form it’s completely cryptic. Descriptive identifiers might help but I’m not even sure about that. In fact, the bit operations to produce the
scenario
value strike me as unnecessarily error-prone.– Konrad Rudolph
Dec 3 at 22:25
I find that binary literals here would be a minimal requirement to make the first code clean. In its current form it’s completely cryptic. Descriptive identifiers might help but I’m not even sure about that. In fact, the bit operations to produce the
scenario
value strike me as unnecessarily error-prone.– Konrad Rudolph
Dec 3 at 22:25
add a comment |
up vote
17
down vote
My previous answer is already the accepted answer, I add something here that I think is both readable, easy and in this case open to future modifications:
Starting with @ZdeslavVojkovic answer (which I find quite good), I came up with this:
#include <iostream>
#include <set>
//using namespace std;
int GetScenarioInt(bool bValue1, bool bValue2, bool bValue3, bool bValue4)
{
return bValue1 << 3 | bValue2 << 2 | bValue3 << 1 | bValue4;
}
bool IsValidScenario(bool bValue1, bool bValue2, bool bValue3, bool bValue4)
{
std::set<int> validScenarios;
validScenarios.insert(GetScenarioInt(true, true, true, true));
validScenarios.insert(GetScenarioInt(true, true, true, false));
validScenarios.insert(GetScenarioInt(true, false, false, false));
int currentScenario = GetScenarioInt(bValue1, bValue2, bValue3, bValue4);
return validScenarios.find(currentScenario) != validScenarios.end();
}
int main()
{
std::cout << IsValidScenario(true, true, true, false) << "n"; // expected = true;
std::cout << IsValidScenario(true, true, false, false) << "n"; // expected = false;
return 0;
}
See it at work here
Well, that's the "elegant and maintainable" (IMHO) solution I usually aim to, but really, for the OP case, my previous "bunch of ifs" answer fits better the OP requirements, even if it's not elegant nor maintainable.
(Almost) off topic:
I don't write lot of answers here at StackOverflow. It's really funny that the above accepted anwser is the most appreciated answer in my history, granting me a couple of badges at SO.
And actually is not what I usually think is the "right" way to do it.
But simplicity is often "the right way to do it", many people seems to think this and I should think it more than I do :)
10
I'd consider removing the last 3 paragraphs as they add nothing to your answer. Consider editing your other answer to add the part about "simplicity is often / always the right way to do something. Readability/maintainability beats a few lines saved".
– Tas
Dec 3 at 21:13
add a comment |
up vote
17
down vote
My previous answer is already the accepted answer, I add something here that I think is both readable, easy and in this case open to future modifications:
Starting with @ZdeslavVojkovic answer (which I find quite good), I came up with this:
#include <iostream>
#include <set>
//using namespace std;
int GetScenarioInt(bool bValue1, bool bValue2, bool bValue3, bool bValue4)
{
return bValue1 << 3 | bValue2 << 2 | bValue3 << 1 | bValue4;
}
bool IsValidScenario(bool bValue1, bool bValue2, bool bValue3, bool bValue4)
{
std::set<int> validScenarios;
validScenarios.insert(GetScenarioInt(true, true, true, true));
validScenarios.insert(GetScenarioInt(true, true, true, false));
validScenarios.insert(GetScenarioInt(true, false, false, false));
int currentScenario = GetScenarioInt(bValue1, bValue2, bValue3, bValue4);
return validScenarios.find(currentScenario) != validScenarios.end();
}
int main()
{
std::cout << IsValidScenario(true, true, true, false) << "n"; // expected = true;
std::cout << IsValidScenario(true, true, false, false) << "n"; // expected = false;
return 0;
}
See it at work here
Well, that's the "elegant and maintainable" (IMHO) solution I usually aim to, but really, for the OP case, my previous "bunch of ifs" answer fits better the OP requirements, even if it's not elegant nor maintainable.
(Almost) off topic:
I don't write lot of answers here at StackOverflow. It's really funny that the above accepted anwser is the most appreciated answer in my history, granting me a couple of badges at SO.
And actually is not what I usually think is the "right" way to do it.
But simplicity is often "the right way to do it", many people seems to think this and I should think it more than I do :)
10
I'd consider removing the last 3 paragraphs as they add nothing to your answer. Consider editing your other answer to add the part about "simplicity is often / always the right way to do something. Readability/maintainability beats a few lines saved".
– Tas
Dec 3 at 21:13
add a comment |
up vote
17
down vote
up vote
17
down vote
My previous answer is already the accepted answer, I add something here that I think is both readable, easy and in this case open to future modifications:
Starting with @ZdeslavVojkovic answer (which I find quite good), I came up with this:
#include <iostream>
#include <set>
//using namespace std;
int GetScenarioInt(bool bValue1, bool bValue2, bool bValue3, bool bValue4)
{
return bValue1 << 3 | bValue2 << 2 | bValue3 << 1 | bValue4;
}
bool IsValidScenario(bool bValue1, bool bValue2, bool bValue3, bool bValue4)
{
std::set<int> validScenarios;
validScenarios.insert(GetScenarioInt(true, true, true, true));
validScenarios.insert(GetScenarioInt(true, true, true, false));
validScenarios.insert(GetScenarioInt(true, false, false, false));
int currentScenario = GetScenarioInt(bValue1, bValue2, bValue3, bValue4);
return validScenarios.find(currentScenario) != validScenarios.end();
}
int main()
{
std::cout << IsValidScenario(true, true, true, false) << "n"; // expected = true;
std::cout << IsValidScenario(true, true, false, false) << "n"; // expected = false;
return 0;
}
See it at work here
Well, that's the "elegant and maintainable" (IMHO) solution I usually aim to, but really, for the OP case, my previous "bunch of ifs" answer fits better the OP requirements, even if it's not elegant nor maintainable.
(Almost) off topic:
I don't write lot of answers here at StackOverflow. It's really funny that the above accepted anwser is the most appreciated answer in my history, granting me a couple of badges at SO.
And actually is not what I usually think is the "right" way to do it.
But simplicity is often "the right way to do it", many people seems to think this and I should think it more than I do :)
My previous answer is already the accepted answer, I add something here that I think is both readable, easy and in this case open to future modifications:
Starting with @ZdeslavVojkovic answer (which I find quite good), I came up with this:
#include <iostream>
#include <set>
//using namespace std;
int GetScenarioInt(bool bValue1, bool bValue2, bool bValue3, bool bValue4)
{
return bValue1 << 3 | bValue2 << 2 | bValue3 << 1 | bValue4;
}
bool IsValidScenario(bool bValue1, bool bValue2, bool bValue3, bool bValue4)
{
std::set<int> validScenarios;
validScenarios.insert(GetScenarioInt(true, true, true, true));
validScenarios.insert(GetScenarioInt(true, true, true, false));
validScenarios.insert(GetScenarioInt(true, false, false, false));
int currentScenario = GetScenarioInt(bValue1, bValue2, bValue3, bValue4);
return validScenarios.find(currentScenario) != validScenarios.end();
}
int main()
{
std::cout << IsValidScenario(true, true, true, false) << "n"; // expected = true;
std::cout << IsValidScenario(true, true, false, false) << "n"; // expected = false;
return 0;
}
See it at work here
Well, that's the "elegant and maintainable" (IMHO) solution I usually aim to, but really, for the OP case, my previous "bunch of ifs" answer fits better the OP requirements, even if it's not elegant nor maintainable.
(Almost) off topic:
I don't write lot of answers here at StackOverflow. It's really funny that the above accepted anwser is the most appreciated answer in my history, granting me a couple of badges at SO.
And actually is not what I usually think is the "right" way to do it.
But simplicity is often "the right way to do it", many people seems to think this and I should think it more than I do :)
edited Dec 3 at 13:54
answered Dec 3 at 13:43
Gian Paolo
2,8492925
2,8492925
10
I'd consider removing the last 3 paragraphs as they add nothing to your answer. Consider editing your other answer to add the part about "simplicity is often / always the right way to do something. Readability/maintainability beats a few lines saved".
– Tas
Dec 3 at 21:13
add a comment |
10
I'd consider removing the last 3 paragraphs as they add nothing to your answer. Consider editing your other answer to add the part about "simplicity is often / always the right way to do something. Readability/maintainability beats a few lines saved".
– Tas
Dec 3 at 21:13
10
10
I'd consider removing the last 3 paragraphs as they add nothing to your answer. Consider editing your other answer to add the part about "simplicity is often / always the right way to do something. Readability/maintainability beats a few lines saved".
– Tas
Dec 3 at 21:13
I'd consider removing the last 3 paragraphs as they add nothing to your answer. Consider editing your other answer to add the part about "simplicity is often / always the right way to do something. Readability/maintainability beats a few lines saved".
– Tas
Dec 3 at 21:13
add a comment |
up vote
13
down vote
I would also like to submit an other approach.
My idea is to convert the bools into an integer and then compare using variadic templates:
unsigned bitmap_from_bools(bool b) {
return b;
}
template<typename... args>
unsigned bitmap_from_bools(bool b, args... pack) {
return (bitmap_from_bools(b) << sizeof...(pack)) | bitmap_from_bools(pack...);
}
int main() {
bool bValue1;
bool bValue2;
bool bValue3;
bool bValue4;
unsigned summary = bitmap_from_bools(bValue1, bValue2, bValue3, bValue4);
if (summary != 0b1111u && summary != 0b1110u && summary != 0b1000u) {
//bad scenario
}
}
Notice how this system can support up to 32 bools as input. replacing the unsigned
with unsigned long long
(or uint64_t
) increases support to 64 cases.
If you dont like the if (summary != 0b1111u && summary != 0b1110u && summary != 0b1000u)
, you could also use yet another variadic template method:
bool equals_any(unsigned target, unsigned compare) {
return target == compare;
}
template<typename... args>
bool equals_any(unsigned target, unsigned compare, args... compare_pack) {
return equals_any(target, compare) ? true : equals_any(target, compare_pack...);
}
int main() {
bool bValue1;
bool bValue2;
bool bValue3;
bool bValue4;
unsigned summary = bitmap_from_bools(bValue1, bValue2, bValue3, bValue4);
if (!equals_any(summary, 0b1111u, 0b1110u, 0b1000u)) {
//bad scenario
}
}
3
Thanks for sharing your alternative approach.
– Andrew Truckle
Dec 3 at 12:39
1
I love this approach, except for the main function’s name: “from bool … to what?” — Why not explicitly,bitmap_from_bools
, orbools_to_bitmap
?
– Konrad Rudolph
Dec 3 at 22:29
yes @KonradRudolph, I couldn't think of a better name, except maybebools_to_unsigned
. Bitmap is a good keyword; edited.
– Stack Danny
2 days ago
I think you wantsummary!= 0b1111u &&...
.a != b || a != c
is always true ifb != c
– MooseBoys
yesterday
@MooseBoys yes, you're right. Thanks
– Stack Danny
yesterday
add a comment |
up vote
13
down vote
I would also like to submit an other approach.
My idea is to convert the bools into an integer and then compare using variadic templates:
unsigned bitmap_from_bools(bool b) {
return b;
}
template<typename... args>
unsigned bitmap_from_bools(bool b, args... pack) {
return (bitmap_from_bools(b) << sizeof...(pack)) | bitmap_from_bools(pack...);
}
int main() {
bool bValue1;
bool bValue2;
bool bValue3;
bool bValue4;
unsigned summary = bitmap_from_bools(bValue1, bValue2, bValue3, bValue4);
if (summary != 0b1111u && summary != 0b1110u && summary != 0b1000u) {
//bad scenario
}
}
Notice how this system can support up to 32 bools as input. replacing the unsigned
with unsigned long long
(or uint64_t
) increases support to 64 cases.
If you dont like the if (summary != 0b1111u && summary != 0b1110u && summary != 0b1000u)
, you could also use yet another variadic template method:
bool equals_any(unsigned target, unsigned compare) {
return target == compare;
}
template<typename... args>
bool equals_any(unsigned target, unsigned compare, args... compare_pack) {
return equals_any(target, compare) ? true : equals_any(target, compare_pack...);
}
int main() {
bool bValue1;
bool bValue2;
bool bValue3;
bool bValue4;
unsigned summary = bitmap_from_bools(bValue1, bValue2, bValue3, bValue4);
if (!equals_any(summary, 0b1111u, 0b1110u, 0b1000u)) {
//bad scenario
}
}
3
Thanks for sharing your alternative approach.
– Andrew Truckle
Dec 3 at 12:39
1
I love this approach, except for the main function’s name: “from bool … to what?” — Why not explicitly,bitmap_from_bools
, orbools_to_bitmap
?
– Konrad Rudolph
Dec 3 at 22:29
yes @KonradRudolph, I couldn't think of a better name, except maybebools_to_unsigned
. Bitmap is a good keyword; edited.
– Stack Danny
2 days ago
I think you wantsummary!= 0b1111u &&...
.a != b || a != c
is always true ifb != c
– MooseBoys
yesterday
@MooseBoys yes, you're right. Thanks
– Stack Danny
yesterday
add a comment |
up vote
13
down vote
up vote
13
down vote
I would also like to submit an other approach.
My idea is to convert the bools into an integer and then compare using variadic templates:
unsigned bitmap_from_bools(bool b) {
return b;
}
template<typename... args>
unsigned bitmap_from_bools(bool b, args... pack) {
return (bitmap_from_bools(b) << sizeof...(pack)) | bitmap_from_bools(pack...);
}
int main() {
bool bValue1;
bool bValue2;
bool bValue3;
bool bValue4;
unsigned summary = bitmap_from_bools(bValue1, bValue2, bValue3, bValue4);
if (summary != 0b1111u && summary != 0b1110u && summary != 0b1000u) {
//bad scenario
}
}
Notice how this system can support up to 32 bools as input. replacing the unsigned
with unsigned long long
(or uint64_t
) increases support to 64 cases.
If you dont like the if (summary != 0b1111u && summary != 0b1110u && summary != 0b1000u)
, you could also use yet another variadic template method:
bool equals_any(unsigned target, unsigned compare) {
return target == compare;
}
template<typename... args>
bool equals_any(unsigned target, unsigned compare, args... compare_pack) {
return equals_any(target, compare) ? true : equals_any(target, compare_pack...);
}
int main() {
bool bValue1;
bool bValue2;
bool bValue3;
bool bValue4;
unsigned summary = bitmap_from_bools(bValue1, bValue2, bValue3, bValue4);
if (!equals_any(summary, 0b1111u, 0b1110u, 0b1000u)) {
//bad scenario
}
}
I would also like to submit an other approach.
My idea is to convert the bools into an integer and then compare using variadic templates:
unsigned bitmap_from_bools(bool b) {
return b;
}
template<typename... args>
unsigned bitmap_from_bools(bool b, args... pack) {
return (bitmap_from_bools(b) << sizeof...(pack)) | bitmap_from_bools(pack...);
}
int main() {
bool bValue1;
bool bValue2;
bool bValue3;
bool bValue4;
unsigned summary = bitmap_from_bools(bValue1, bValue2, bValue3, bValue4);
if (summary != 0b1111u && summary != 0b1110u && summary != 0b1000u) {
//bad scenario
}
}
Notice how this system can support up to 32 bools as input. replacing the unsigned
with unsigned long long
(or uint64_t
) increases support to 64 cases.
If you dont like the if (summary != 0b1111u && summary != 0b1110u && summary != 0b1000u)
, you could also use yet another variadic template method:
bool equals_any(unsigned target, unsigned compare) {
return target == compare;
}
template<typename... args>
bool equals_any(unsigned target, unsigned compare, args... compare_pack) {
return equals_any(target, compare) ? true : equals_any(target, compare_pack...);
}
int main() {
bool bValue1;
bool bValue2;
bool bValue3;
bool bValue4;
unsigned summary = bitmap_from_bools(bValue1, bValue2, bValue3, bValue4);
if (!equals_any(summary, 0b1111u, 0b1110u, 0b1000u)) {
//bad scenario
}
}
edited yesterday
answered Dec 3 at 11:28
Stack Danny
1,015319
1,015319
3
Thanks for sharing your alternative approach.
– Andrew Truckle
Dec 3 at 12:39
1
I love this approach, except for the main function’s name: “from bool … to what?” — Why not explicitly,bitmap_from_bools
, orbools_to_bitmap
?
– Konrad Rudolph
Dec 3 at 22:29
yes @KonradRudolph, I couldn't think of a better name, except maybebools_to_unsigned
. Bitmap is a good keyword; edited.
– Stack Danny
2 days ago
I think you wantsummary!= 0b1111u &&...
.a != b || a != c
is always true ifb != c
– MooseBoys
yesterday
@MooseBoys yes, you're right. Thanks
– Stack Danny
yesterday
add a comment |
3
Thanks for sharing your alternative approach.
– Andrew Truckle
Dec 3 at 12:39
1
I love this approach, except for the main function’s name: “from bool … to what?” — Why not explicitly,bitmap_from_bools
, orbools_to_bitmap
?
– Konrad Rudolph
Dec 3 at 22:29
yes @KonradRudolph, I couldn't think of a better name, except maybebools_to_unsigned
. Bitmap is a good keyword; edited.
– Stack Danny
2 days ago
I think you wantsummary!= 0b1111u &&...
.a != b || a != c
is always true ifb != c
– MooseBoys
yesterday
@MooseBoys yes, you're right. Thanks
– Stack Danny
yesterday
3
3
Thanks for sharing your alternative approach.
– Andrew Truckle
Dec 3 at 12:39
Thanks for sharing your alternative approach.
– Andrew Truckle
Dec 3 at 12:39
1
1
I love this approach, except for the main function’s name: “from bool … to what?” — Why not explicitly,
bitmap_from_bools
, or bools_to_bitmap
?– Konrad Rudolph
Dec 3 at 22:29
I love this approach, except for the main function’s name: “from bool … to what?” — Why not explicitly,
bitmap_from_bools
, or bools_to_bitmap
?– Konrad Rudolph
Dec 3 at 22:29
yes @KonradRudolph, I couldn't think of a better name, except maybe
bools_to_unsigned
. Bitmap is a good keyword; edited.– Stack Danny
2 days ago
yes @KonradRudolph, I couldn't think of a better name, except maybe
bools_to_unsigned
. Bitmap is a good keyword; edited.– Stack Danny
2 days ago
I think you want
summary!= 0b1111u &&...
. a != b || a != c
is always true if b != c
– MooseBoys
yesterday
I think you want
summary!= 0b1111u &&...
. a != b || a != c
is always true if b != c
– MooseBoys
yesterday
@MooseBoys yes, you're right. Thanks
– Stack Danny
yesterday
@MooseBoys yes, you're right. Thanks
– Stack Danny
yesterday
add a comment |
up vote
11
down vote
Here's a simplified version:
if (bValue1&&(bValue2==bValue3)&&(bValue2||!bValue4)) {
// acceptable
} else {
// not acceptable
}
Note, of course, this solution is more obfuscated than the original one, its meaning may be harder to understand.
Update: MSalters in the comments found an even simpler expression:
if (bValue1&&(bValue2==bValue3)&&(bValue2>=bValue4)) ...
Yes, but hard to understand. But thanks for suggestion.
– Andrew Truckle
Dec 3 at 10:58
I compared compilers ability to simplify expression with your simplification as a reference: compiler explorer. gcc did not find your optimal version but its solution is still good. Clang and MSVC don't seem to perform any boolean expression simplification.
– Oliv
Dec 3 at 11:07
1
@AndrewTruckle: note, that if you needed a more readable version, then please say so. You've said "simplified", yet you accept an even more verbose version than your original one.
– geza
Dec 3 at 11:12
@Oliv: thanks for doing this test! This proves the point that while compilers are getting better and better, they still have a lot to learn :)
– geza
Dec 3 at 11:15
1
simple
is indeed a vague term. Many people understand it in this context as simpler for developer to understand and not for the compiler to generate code, so more verbose can indeed be simpler.
– Zdeslav Vojkovic
Dec 3 at 11:16
|
show 5 more comments
up vote
11
down vote
Here's a simplified version:
if (bValue1&&(bValue2==bValue3)&&(bValue2||!bValue4)) {
// acceptable
} else {
// not acceptable
}
Note, of course, this solution is more obfuscated than the original one, its meaning may be harder to understand.
Update: MSalters in the comments found an even simpler expression:
if (bValue1&&(bValue2==bValue3)&&(bValue2>=bValue4)) ...
Yes, but hard to understand. But thanks for suggestion.
– Andrew Truckle
Dec 3 at 10:58
I compared compilers ability to simplify expression with your simplification as a reference: compiler explorer. gcc did not find your optimal version but its solution is still good. Clang and MSVC don't seem to perform any boolean expression simplification.
– Oliv
Dec 3 at 11:07
1
@AndrewTruckle: note, that if you needed a more readable version, then please say so. You've said "simplified", yet you accept an even more verbose version than your original one.
– geza
Dec 3 at 11:12
@Oliv: thanks for doing this test! This proves the point that while compilers are getting better and better, they still have a lot to learn :)
– geza
Dec 3 at 11:15
1
simple
is indeed a vague term. Many people understand it in this context as simpler for developer to understand and not for the compiler to generate code, so more verbose can indeed be simpler.
– Zdeslav Vojkovic
Dec 3 at 11:16
|
show 5 more comments
up vote
11
down vote
up vote
11
down vote
Here's a simplified version:
if (bValue1&&(bValue2==bValue3)&&(bValue2||!bValue4)) {
// acceptable
} else {
// not acceptable
}
Note, of course, this solution is more obfuscated than the original one, its meaning may be harder to understand.
Update: MSalters in the comments found an even simpler expression:
if (bValue1&&(bValue2==bValue3)&&(bValue2>=bValue4)) ...
Here's a simplified version:
if (bValue1&&(bValue2==bValue3)&&(bValue2||!bValue4)) {
// acceptable
} else {
// not acceptable
}
Note, of course, this solution is more obfuscated than the original one, its meaning may be harder to understand.
Update: MSalters in the comments found an even simpler expression:
if (bValue1&&(bValue2==bValue3)&&(bValue2>=bValue4)) ...
edited Dec 3 at 16:25
answered Dec 3 at 10:40
geza
12.3k32774
12.3k32774
Yes, but hard to understand. But thanks for suggestion.
– Andrew Truckle
Dec 3 at 10:58
I compared compilers ability to simplify expression with your simplification as a reference: compiler explorer. gcc did not find your optimal version but its solution is still good. Clang and MSVC don't seem to perform any boolean expression simplification.
– Oliv
Dec 3 at 11:07
1
@AndrewTruckle: note, that if you needed a more readable version, then please say so. You've said "simplified", yet you accept an even more verbose version than your original one.
– geza
Dec 3 at 11:12
@Oliv: thanks for doing this test! This proves the point that while compilers are getting better and better, they still have a lot to learn :)
– geza
Dec 3 at 11:15
1
simple
is indeed a vague term. Many people understand it in this context as simpler for developer to understand and not for the compiler to generate code, so more verbose can indeed be simpler.
– Zdeslav Vojkovic
Dec 3 at 11:16
|
show 5 more comments
Yes, but hard to understand. But thanks for suggestion.
– Andrew Truckle
Dec 3 at 10:58
I compared compilers ability to simplify expression with your simplification as a reference: compiler explorer. gcc did not find your optimal version but its solution is still good. Clang and MSVC don't seem to perform any boolean expression simplification.
– Oliv
Dec 3 at 11:07
1
@AndrewTruckle: note, that if you needed a more readable version, then please say so. You've said "simplified", yet you accept an even more verbose version than your original one.
– geza
Dec 3 at 11:12
@Oliv: thanks for doing this test! This proves the point that while compilers are getting better and better, they still have a lot to learn :)
– geza
Dec 3 at 11:15
1
simple
is indeed a vague term. Many people understand it in this context as simpler for developer to understand and not for the compiler to generate code, so more verbose can indeed be simpler.
– Zdeslav Vojkovic
Dec 3 at 11:16
Yes, but hard to understand. But thanks for suggestion.
– Andrew Truckle
Dec 3 at 10:58
Yes, but hard to understand. But thanks for suggestion.
– Andrew Truckle
Dec 3 at 10:58
I compared compilers ability to simplify expression with your simplification as a reference: compiler explorer. gcc did not find your optimal version but its solution is still good. Clang and MSVC don't seem to perform any boolean expression simplification.
– Oliv
Dec 3 at 11:07
I compared compilers ability to simplify expression with your simplification as a reference: compiler explorer. gcc did not find your optimal version but its solution is still good. Clang and MSVC don't seem to perform any boolean expression simplification.
– Oliv
Dec 3 at 11:07
1
1
@AndrewTruckle: note, that if you needed a more readable version, then please say so. You've said "simplified", yet you accept an even more verbose version than your original one.
– geza
Dec 3 at 11:12
@AndrewTruckle: note, that if you needed a more readable version, then please say so. You've said "simplified", yet you accept an even more verbose version than your original one.
– geza
Dec 3 at 11:12
@Oliv: thanks for doing this test! This proves the point that while compilers are getting better and better, they still have a lot to learn :)
– geza
Dec 3 at 11:15
@Oliv: thanks for doing this test! This proves the point that while compilers are getting better and better, they still have a lot to learn :)
– geza
Dec 3 at 11:15
1
1
simple
is indeed a vague term. Many people understand it in this context as simpler for developer to understand and not for the compiler to generate code, so more verbose can indeed be simpler.– Zdeslav Vojkovic
Dec 3 at 11:16
simple
is indeed a vague term. Many people understand it in this context as simpler for developer to understand and not for the compiler to generate code, so more verbose can indeed be simpler.– Zdeslav Vojkovic
Dec 3 at 11:16
|
show 5 more comments
up vote
7
down vote
I'm not seeing any answers saying to name the scenarios, though the OP's solution does exactly that.
To me it is best to encapsulate the comment of what each scenario is into either a variable name or function name. You're more likely to ignore a comment than a name, and if your logic changes in the future you're more likely to change a name than a comment. You can't refactor a comment.
If you plan on reusing these scenarios outside of your function (or might want to), then make a function that says what it evaluates (constexpr
/noexcept
optional but recommended):
constexpr bool IsScenario1(bool b1, bool b2, bool b3, bool b4) noexcept
{ return b1 && b2 && b3 && b4; }
constexpr bool IsScenario2(bool b1, bool b2, bool b3, bool b4) noexcept
{ return b1 && b2 && b3 && !b4; }
constexpr bool IsScenario3(bool b1, bool b2, bool b3, bool b4) noexcept
{ return b1 && !b2 && !b3 && !b4; }
Make these class methods if possible (like in OP's solution). You can use variables inside of your function if you don't think you'll reuse the logic:
const auto is_scenario_1 = bValue1 && bValue2 && bValue3 && bValue4;
const auto is_scenario_2 = bvalue1 && bvalue2 && bValue3 && !bValue4;
const auto is_scenario_3 = bValue1 && !bValue2 && !bValue3 && !bValue4;
The compiler will most likely sort out that if bValue1 is false then all scenarios are false. Don't worry about making it fast, just correct and readable. If you profile your code and find this to be a bottleneck because the compiler generated sub-optimal code at -O2 or higher then try to rewrite it.
I like this slightly more than Gian Paolo's (already nice) solution: It avoids control flow and the use of a variable that is overwritten - more functional style.
– Dirk Herrmann
Dec 3 at 23:53
add a comment |
up vote
7
down vote
I'm not seeing any answers saying to name the scenarios, though the OP's solution does exactly that.
To me it is best to encapsulate the comment of what each scenario is into either a variable name or function name. You're more likely to ignore a comment than a name, and if your logic changes in the future you're more likely to change a name than a comment. You can't refactor a comment.
If you plan on reusing these scenarios outside of your function (or might want to), then make a function that says what it evaluates (constexpr
/noexcept
optional but recommended):
constexpr bool IsScenario1(bool b1, bool b2, bool b3, bool b4) noexcept
{ return b1 && b2 && b3 && b4; }
constexpr bool IsScenario2(bool b1, bool b2, bool b3, bool b4) noexcept
{ return b1 && b2 && b3 && !b4; }
constexpr bool IsScenario3(bool b1, bool b2, bool b3, bool b4) noexcept
{ return b1 && !b2 && !b3 && !b4; }
Make these class methods if possible (like in OP's solution). You can use variables inside of your function if you don't think you'll reuse the logic:
const auto is_scenario_1 = bValue1 && bValue2 && bValue3 && bValue4;
const auto is_scenario_2 = bvalue1 && bvalue2 && bValue3 && !bValue4;
const auto is_scenario_3 = bValue1 && !bValue2 && !bValue3 && !bValue4;
The compiler will most likely sort out that if bValue1 is false then all scenarios are false. Don't worry about making it fast, just correct and readable. If you profile your code and find this to be a bottleneck because the compiler generated sub-optimal code at -O2 or higher then try to rewrite it.
I like this slightly more than Gian Paolo's (already nice) solution: It avoids control flow and the use of a variable that is overwritten - more functional style.
– Dirk Herrmann
Dec 3 at 23:53
add a comment |
up vote
7
down vote
up vote
7
down vote
I'm not seeing any answers saying to name the scenarios, though the OP's solution does exactly that.
To me it is best to encapsulate the comment of what each scenario is into either a variable name or function name. You're more likely to ignore a comment than a name, and if your logic changes in the future you're more likely to change a name than a comment. You can't refactor a comment.
If you plan on reusing these scenarios outside of your function (or might want to), then make a function that says what it evaluates (constexpr
/noexcept
optional but recommended):
constexpr bool IsScenario1(bool b1, bool b2, bool b3, bool b4) noexcept
{ return b1 && b2 && b3 && b4; }
constexpr bool IsScenario2(bool b1, bool b2, bool b3, bool b4) noexcept
{ return b1 && b2 && b3 && !b4; }
constexpr bool IsScenario3(bool b1, bool b2, bool b3, bool b4) noexcept
{ return b1 && !b2 && !b3 && !b4; }
Make these class methods if possible (like in OP's solution). You can use variables inside of your function if you don't think you'll reuse the logic:
const auto is_scenario_1 = bValue1 && bValue2 && bValue3 && bValue4;
const auto is_scenario_2 = bvalue1 && bvalue2 && bValue3 && !bValue4;
const auto is_scenario_3 = bValue1 && !bValue2 && !bValue3 && !bValue4;
The compiler will most likely sort out that if bValue1 is false then all scenarios are false. Don't worry about making it fast, just correct and readable. If you profile your code and find this to be a bottleneck because the compiler generated sub-optimal code at -O2 or higher then try to rewrite it.
I'm not seeing any answers saying to name the scenarios, though the OP's solution does exactly that.
To me it is best to encapsulate the comment of what each scenario is into either a variable name or function name. You're more likely to ignore a comment than a name, and if your logic changes in the future you're more likely to change a name than a comment. You can't refactor a comment.
If you plan on reusing these scenarios outside of your function (or might want to), then make a function that says what it evaluates (constexpr
/noexcept
optional but recommended):
constexpr bool IsScenario1(bool b1, bool b2, bool b3, bool b4) noexcept
{ return b1 && b2 && b3 && b4; }
constexpr bool IsScenario2(bool b1, bool b2, bool b3, bool b4) noexcept
{ return b1 && b2 && b3 && !b4; }
constexpr bool IsScenario3(bool b1, bool b2, bool b3, bool b4) noexcept
{ return b1 && !b2 && !b3 && !b4; }
Make these class methods if possible (like in OP's solution). You can use variables inside of your function if you don't think you'll reuse the logic:
const auto is_scenario_1 = bValue1 && bValue2 && bValue3 && bValue4;
const auto is_scenario_2 = bvalue1 && bvalue2 && bValue3 && !bValue4;
const auto is_scenario_3 = bValue1 && !bValue2 && !bValue3 && !bValue4;
The compiler will most likely sort out that if bValue1 is false then all scenarios are false. Don't worry about making it fast, just correct and readable. If you profile your code and find this to be a bottleneck because the compiler generated sub-optimal code at -O2 or higher then try to rewrite it.
edited 2 days ago
Andrew Truckle
5,16032145
5,16032145
answered Dec 3 at 23:13
Erroneous
470410
470410
I like this slightly more than Gian Paolo's (already nice) solution: It avoids control flow and the use of a variable that is overwritten - more functional style.
– Dirk Herrmann
Dec 3 at 23:53
add a comment |
I like this slightly more than Gian Paolo's (already nice) solution: It avoids control flow and the use of a variable that is overwritten - more functional style.
– Dirk Herrmann
Dec 3 at 23:53
I like this slightly more than Gian Paolo's (already nice) solution: It avoids control flow and the use of a variable that is overwritten - more functional style.
– Dirk Herrmann
Dec 3 at 23:53
I like this slightly more than Gian Paolo's (already nice) solution: It avoids control flow and the use of a variable that is overwritten - more functional style.
– Dirk Herrmann
Dec 3 at 23:53
add a comment |
up vote
6
down vote
I am only providing my answer here as in the comments someone suggested to show my solution. I want to thank everyone for their insights.
In the end I opted to add three new "scenario" boolean
methods:
bool CChristianLifeMinistryValidationDlg::IsFirstWeekStudentItems(CChristianLifeMinistryEntry *pEntry)
{
return (INCLUDE_ITEM1(pEntry) &&
!INCLUDE_ITEM2(pEntry) &&
!INCLUDE_ITEM3(pEntry) &&
!INCLUDE_ITEM4(pEntry));
}
bool CChristianLifeMinistryValidationDlg::IsSecondWeekStudentItems(CChristianLifeMinistryEntry *pEntry)
{
return (INCLUDE_ITEM1(pEntry) &&
INCLUDE_ITEM2(pEntry) &&
INCLUDE_ITEM3(pEntry) &&
INCLUDE_ITEM4(pEntry));
}
bool CChristianLifeMinistryValidationDlg::IsOtherWeekStudentItems(CChristianLifeMinistryEntry *pEntry)
{
return (INCLUDE_ITEM1(pEntry) &&
INCLUDE_ITEM2(pEntry) &&
INCLUDE_ITEM3(pEntry) &&
!INCLUDE_ITEM4(pEntry));
}
Then I was able to apply those my my validation routine like this:
if (!IsFirstWeekStudentItems(pEntry) && !IsSecondWeekStudentItems(pEntry) && !IsOtherWeekStudentItems(pEntry))
{
; Error
}
In my live application the 4 bool values are actually extracted from a DWORD
which has 4 values encoded into it.
Thanks again everyone.
1
Thanks for sharing the solution. :) It's actually better than the complex if conditions hell. Maybe you can still nameINCLUDE_ITEM1
etc in a better way and you are all good. :)
– Hardik Modha
Dec 3 at 13:04
1
@HardikModha Well, technically they are "Student items" and the flag is to indicate if they are to be "included". So I think the name, albeit sounding generic, is actually meaningful in this context. :)
– Andrew Truckle
Dec 3 at 13:06
Well, Sounds good then. :)
– Hardik Modha
Dec 3 at 13:10
add a comment |
up vote
6
down vote
I am only providing my answer here as in the comments someone suggested to show my solution. I want to thank everyone for their insights.
In the end I opted to add three new "scenario" boolean
methods:
bool CChristianLifeMinistryValidationDlg::IsFirstWeekStudentItems(CChristianLifeMinistryEntry *pEntry)
{
return (INCLUDE_ITEM1(pEntry) &&
!INCLUDE_ITEM2(pEntry) &&
!INCLUDE_ITEM3(pEntry) &&
!INCLUDE_ITEM4(pEntry));
}
bool CChristianLifeMinistryValidationDlg::IsSecondWeekStudentItems(CChristianLifeMinistryEntry *pEntry)
{
return (INCLUDE_ITEM1(pEntry) &&
INCLUDE_ITEM2(pEntry) &&
INCLUDE_ITEM3(pEntry) &&
INCLUDE_ITEM4(pEntry));
}
bool CChristianLifeMinistryValidationDlg::IsOtherWeekStudentItems(CChristianLifeMinistryEntry *pEntry)
{
return (INCLUDE_ITEM1(pEntry) &&
INCLUDE_ITEM2(pEntry) &&
INCLUDE_ITEM3(pEntry) &&
!INCLUDE_ITEM4(pEntry));
}
Then I was able to apply those my my validation routine like this:
if (!IsFirstWeekStudentItems(pEntry) && !IsSecondWeekStudentItems(pEntry) && !IsOtherWeekStudentItems(pEntry))
{
; Error
}
In my live application the 4 bool values are actually extracted from a DWORD
which has 4 values encoded into it.
Thanks again everyone.
1
Thanks for sharing the solution. :) It's actually better than the complex if conditions hell. Maybe you can still nameINCLUDE_ITEM1
etc in a better way and you are all good. :)
– Hardik Modha
Dec 3 at 13:04
1
@HardikModha Well, technically they are "Student items" and the flag is to indicate if they are to be "included". So I think the name, albeit sounding generic, is actually meaningful in this context. :)
– Andrew Truckle
Dec 3 at 13:06
Well, Sounds good then. :)
– Hardik Modha
Dec 3 at 13:10
add a comment |
up vote
6
down vote
up vote
6
down vote
I am only providing my answer here as in the comments someone suggested to show my solution. I want to thank everyone for their insights.
In the end I opted to add three new "scenario" boolean
methods:
bool CChristianLifeMinistryValidationDlg::IsFirstWeekStudentItems(CChristianLifeMinistryEntry *pEntry)
{
return (INCLUDE_ITEM1(pEntry) &&
!INCLUDE_ITEM2(pEntry) &&
!INCLUDE_ITEM3(pEntry) &&
!INCLUDE_ITEM4(pEntry));
}
bool CChristianLifeMinistryValidationDlg::IsSecondWeekStudentItems(CChristianLifeMinistryEntry *pEntry)
{
return (INCLUDE_ITEM1(pEntry) &&
INCLUDE_ITEM2(pEntry) &&
INCLUDE_ITEM3(pEntry) &&
INCLUDE_ITEM4(pEntry));
}
bool CChristianLifeMinistryValidationDlg::IsOtherWeekStudentItems(CChristianLifeMinistryEntry *pEntry)
{
return (INCLUDE_ITEM1(pEntry) &&
INCLUDE_ITEM2(pEntry) &&
INCLUDE_ITEM3(pEntry) &&
!INCLUDE_ITEM4(pEntry));
}
Then I was able to apply those my my validation routine like this:
if (!IsFirstWeekStudentItems(pEntry) && !IsSecondWeekStudentItems(pEntry) && !IsOtherWeekStudentItems(pEntry))
{
; Error
}
In my live application the 4 bool values are actually extracted from a DWORD
which has 4 values encoded into it.
Thanks again everyone.
I am only providing my answer here as in the comments someone suggested to show my solution. I want to thank everyone for their insights.
In the end I opted to add three new "scenario" boolean
methods:
bool CChristianLifeMinistryValidationDlg::IsFirstWeekStudentItems(CChristianLifeMinistryEntry *pEntry)
{
return (INCLUDE_ITEM1(pEntry) &&
!INCLUDE_ITEM2(pEntry) &&
!INCLUDE_ITEM3(pEntry) &&
!INCLUDE_ITEM4(pEntry));
}
bool CChristianLifeMinistryValidationDlg::IsSecondWeekStudentItems(CChristianLifeMinistryEntry *pEntry)
{
return (INCLUDE_ITEM1(pEntry) &&
INCLUDE_ITEM2(pEntry) &&
INCLUDE_ITEM3(pEntry) &&
INCLUDE_ITEM4(pEntry));
}
bool CChristianLifeMinistryValidationDlg::IsOtherWeekStudentItems(CChristianLifeMinistryEntry *pEntry)
{
return (INCLUDE_ITEM1(pEntry) &&
INCLUDE_ITEM2(pEntry) &&
INCLUDE_ITEM3(pEntry) &&
!INCLUDE_ITEM4(pEntry));
}
Then I was able to apply those my my validation routine like this:
if (!IsFirstWeekStudentItems(pEntry) && !IsSecondWeekStudentItems(pEntry) && !IsOtherWeekStudentItems(pEntry))
{
; Error
}
In my live application the 4 bool values are actually extracted from a DWORD
which has 4 values encoded into it.
Thanks again everyone.
answered Dec 3 at 13:01
Andrew Truckle
5,16032145
5,16032145
1
Thanks for sharing the solution. :) It's actually better than the complex if conditions hell. Maybe you can still nameINCLUDE_ITEM1
etc in a better way and you are all good. :)
– Hardik Modha
Dec 3 at 13:04
1
@HardikModha Well, technically they are "Student items" and the flag is to indicate if they are to be "included". So I think the name, albeit sounding generic, is actually meaningful in this context. :)
– Andrew Truckle
Dec 3 at 13:06
Well, Sounds good then. :)
– Hardik Modha
Dec 3 at 13:10
add a comment |
1
Thanks for sharing the solution. :) It's actually better than the complex if conditions hell. Maybe you can still nameINCLUDE_ITEM1
etc in a better way and you are all good. :)
– Hardik Modha
Dec 3 at 13:04
1
@HardikModha Well, technically they are "Student items" and the flag is to indicate if they are to be "included". So I think the name, albeit sounding generic, is actually meaningful in this context. :)
– Andrew Truckle
Dec 3 at 13:06
Well, Sounds good then. :)
– Hardik Modha
Dec 3 at 13:10
1
1
Thanks for sharing the solution. :) It's actually better than the complex if conditions hell. Maybe you can still name
INCLUDE_ITEM1
etc in a better way and you are all good. :)– Hardik Modha
Dec 3 at 13:04
Thanks for sharing the solution. :) It's actually better than the complex if conditions hell. Maybe you can still name
INCLUDE_ITEM1
etc in a better way and you are all good. :)– Hardik Modha
Dec 3 at 13:04
1
1
@HardikModha Well, technically they are "Student items" and the flag is to indicate if they are to be "included". So I think the name, albeit sounding generic, is actually meaningful in this context. :)
– Andrew Truckle
Dec 3 at 13:06
@HardikModha Well, technically they are "Student items" and the flag is to indicate if they are to be "included". So I think the name, albeit sounding generic, is actually meaningful in this context. :)
– Andrew Truckle
Dec 3 at 13:06
Well, Sounds good then. :)
– Hardik Modha
Dec 3 at 13:10
Well, Sounds good then. :)
– Hardik Modha
Dec 3 at 13:10
add a comment |
up vote
5
down vote
A C/C++ way
bool scenario[3][4] = {{true, true, true, true},
{true, true, true, false},
{true, false, false, false}};
bool CheckScenario(bool bValue1, bool bValue2, bool bValue3, bool bValue4)
{
bool temp = {bValue1, bValue2, bValue3, bValue4};
for(int i = 0 ; i < sizeof(scenario) / sizeof(scenario[0]); i++)
{
if(memcmp(temp, scenario[i], sizeof(temp)) == 0)
return true;
}
return false;
}
This approach is scalable as if the number of valid conditions grow, you easily just add more of them to scenario list.
Thank you for your answer.
– Andrew Truckle
Dec 3 at 12:36
I'm pretty sure this is wrong, though. It assumes that the compiler uses only a single binary representation fortrue
. A compiler which uses "anything non-zero is true" causes this code to fail. Note thattrue
must convert to1
, it just doesn't need to be stored as such.
– MSalters
Dec 3 at 15:43
@MSalters, tnx, I get your point and I am aware of that, kinda like2 is not equal to true but evaluates to true
, my code doesnt forceint 1 = true
and works as long as all true's are converted to same int value, SO here is my question: Why compiler should act random on converting true to underlying int, Can you please elaborate more?
– hessam hedieh
Dec 3 at 16:01
Performing amemcmp
to test boolean conditions is not the C++ way, and I rather doubt that it’s an established C way, either.
– Konrad Rudolph
Dec 3 at 22:27
@hessamhedieh: The problem in your logic is "converting true to underlying int". That is not how compilers work,
– MSalters
2 days ago
|
show 1 more comment
up vote
5
down vote
A C/C++ way
bool scenario[3][4] = {{true, true, true, true},
{true, true, true, false},
{true, false, false, false}};
bool CheckScenario(bool bValue1, bool bValue2, bool bValue3, bool bValue4)
{
bool temp = {bValue1, bValue2, bValue3, bValue4};
for(int i = 0 ; i < sizeof(scenario) / sizeof(scenario[0]); i++)
{
if(memcmp(temp, scenario[i], sizeof(temp)) == 0)
return true;
}
return false;
}
This approach is scalable as if the number of valid conditions grow, you easily just add more of them to scenario list.
Thank you for your answer.
– Andrew Truckle
Dec 3 at 12:36
I'm pretty sure this is wrong, though. It assumes that the compiler uses only a single binary representation fortrue
. A compiler which uses "anything non-zero is true" causes this code to fail. Note thattrue
must convert to1
, it just doesn't need to be stored as such.
– MSalters
Dec 3 at 15:43
@MSalters, tnx, I get your point and I am aware of that, kinda like2 is not equal to true but evaluates to true
, my code doesnt forceint 1 = true
and works as long as all true's are converted to same int value, SO here is my question: Why compiler should act random on converting true to underlying int, Can you please elaborate more?
– hessam hedieh
Dec 3 at 16:01
Performing amemcmp
to test boolean conditions is not the C++ way, and I rather doubt that it’s an established C way, either.
– Konrad Rudolph
Dec 3 at 22:27
@hessamhedieh: The problem in your logic is "converting true to underlying int". That is not how compilers work,
– MSalters
2 days ago
|
show 1 more comment
up vote
5
down vote
up vote
5
down vote
A C/C++ way
bool scenario[3][4] = {{true, true, true, true},
{true, true, true, false},
{true, false, false, false}};
bool CheckScenario(bool bValue1, bool bValue2, bool bValue3, bool bValue4)
{
bool temp = {bValue1, bValue2, bValue3, bValue4};
for(int i = 0 ; i < sizeof(scenario) / sizeof(scenario[0]); i++)
{
if(memcmp(temp, scenario[i], sizeof(temp)) == 0)
return true;
}
return false;
}
This approach is scalable as if the number of valid conditions grow, you easily just add more of them to scenario list.
A C/C++ way
bool scenario[3][4] = {{true, true, true, true},
{true, true, true, false},
{true, false, false, false}};
bool CheckScenario(bool bValue1, bool bValue2, bool bValue3, bool bValue4)
{
bool temp = {bValue1, bValue2, bValue3, bValue4};
for(int i = 0 ; i < sizeof(scenario) / sizeof(scenario[0]); i++)
{
if(memcmp(temp, scenario[i], sizeof(temp)) == 0)
return true;
}
return false;
}
This approach is scalable as if the number of valid conditions grow, you easily just add more of them to scenario list.
answered Dec 3 at 10:42
hessam hedieh
1455
1455
Thank you for your answer.
– Andrew Truckle
Dec 3 at 12:36
I'm pretty sure this is wrong, though. It assumes that the compiler uses only a single binary representation fortrue
. A compiler which uses "anything non-zero is true" causes this code to fail. Note thattrue
must convert to1
, it just doesn't need to be stored as such.
– MSalters
Dec 3 at 15:43
@MSalters, tnx, I get your point and I am aware of that, kinda like2 is not equal to true but evaluates to true
, my code doesnt forceint 1 = true
and works as long as all true's are converted to same int value, SO here is my question: Why compiler should act random on converting true to underlying int, Can you please elaborate more?
– hessam hedieh
Dec 3 at 16:01
Performing amemcmp
to test boolean conditions is not the C++ way, and I rather doubt that it’s an established C way, either.
– Konrad Rudolph
Dec 3 at 22:27
@hessamhedieh: The problem in your logic is "converting true to underlying int". That is not how compilers work,
– MSalters
2 days ago
|
show 1 more comment
Thank you for your answer.
– Andrew Truckle
Dec 3 at 12:36
I'm pretty sure this is wrong, though. It assumes that the compiler uses only a single binary representation fortrue
. A compiler which uses "anything non-zero is true" causes this code to fail. Note thattrue
must convert to1
, it just doesn't need to be stored as such.
– MSalters
Dec 3 at 15:43
@MSalters, tnx, I get your point and I am aware of that, kinda like2 is not equal to true but evaluates to true
, my code doesnt forceint 1 = true
and works as long as all true's are converted to same int value, SO here is my question: Why compiler should act random on converting true to underlying int, Can you please elaborate more?
– hessam hedieh
Dec 3 at 16:01
Performing amemcmp
to test boolean conditions is not the C++ way, and I rather doubt that it’s an established C way, either.
– Konrad Rudolph
Dec 3 at 22:27
@hessamhedieh: The problem in your logic is "converting true to underlying int". That is not how compilers work,
– MSalters
2 days ago
Thank you for your answer.
– Andrew Truckle
Dec 3 at 12:36
Thank you for your answer.
– Andrew Truckle
Dec 3 at 12:36
I'm pretty sure this is wrong, though. It assumes that the compiler uses only a single binary representation for
true
. A compiler which uses "anything non-zero is true" causes this code to fail. Note that true
must convert to 1
, it just doesn't need to be stored as such.– MSalters
Dec 3 at 15:43
I'm pretty sure this is wrong, though. It assumes that the compiler uses only a single binary representation for
true
. A compiler which uses "anything non-zero is true" causes this code to fail. Note that true
must convert to 1
, it just doesn't need to be stored as such.– MSalters
Dec 3 at 15:43
@MSalters, tnx, I get your point and I am aware of that, kinda like
2 is not equal to true but evaluates to true
, my code doesnt force int 1 = true
and works as long as all true's are converted to same int value, SO here is my question: Why compiler should act random on converting true to underlying int, Can you please elaborate more?– hessam hedieh
Dec 3 at 16:01
@MSalters, tnx, I get your point and I am aware of that, kinda like
2 is not equal to true but evaluates to true
, my code doesnt force int 1 = true
and works as long as all true's are converted to same int value, SO here is my question: Why compiler should act random on converting true to underlying int, Can you please elaborate more?– hessam hedieh
Dec 3 at 16:01
Performing a
memcmp
to test boolean conditions is not the C++ way, and I rather doubt that it’s an established C way, either.– Konrad Rudolph
Dec 3 at 22:27
Performing a
memcmp
to test boolean conditions is not the C++ way, and I rather doubt that it’s an established C way, either.– Konrad Rudolph
Dec 3 at 22:27
@hessamhedieh: The problem in your logic is "converting true to underlying int". That is not how compilers work,
– MSalters
2 days ago
@hessamhedieh: The problem in your logic is "converting true to underlying int". That is not how compilers work,
– MSalters
2 days ago
|
show 1 more comment
up vote
5
down vote
It's easy to notice that first two scenarios are similar - they share most of the conditions. If you want to select in which scenario you are at the moment, you could write it like this (it's a modified @gian-paolo's solution):
bool valid = false;
if(bValue1 && bValue2 && bValue3)
{
if (bValue4)
valid = true; //scenario 1
else if (!bValue4)
valid = true; //scenario 2
}
else if (bValue1 && !bValue2 && !bValue3 && !bValue4)
valid = true; //scenario 3
Going further, you can notice, that first boolean needs to be always true, which is an entry condition, so you can end up with:
bool valid = false;
if(bValue1)
{
if(bValue2 && bValue3)
{
if (bValue4)
valid = true; //scenario 1
else if (!bValue4)
valid = true; //scenario 2
}
else if (!bValue2 && !bValue3 && !bValue4)
valid = true; //scenario 3
}
Even more, you can now clearly see, that bValue2 and bValue3 are somewhat connected - you could extract their state to some external functions or variables with more appropriate name (this is not always easy or appropriate though):
bool valid = false;
if(bValue1)
{
bool bValue1and2 = bValue1 && bValue2;
bool notBValue1and2 = !bValue2 && !bValue3;
if(bValue1and2)
{
if (bValue4)
valid = true; //scenario 1
else if (!bValue4)
valid = true; //scenario 2
}
else if (notBValue1and2 && !bValue4)
valid = true; //scenario 3
}
Doing it this way have some advantages and disadvantages:
- conditions are smaller, so it's easier to reason about them,
- it's easier to do nice renaming to make these conditions more understandable,
- but, they require to understand the scope,
- moreover it's more rigid
If you predict that there will be changes to the above logic, you should use more straightforward approach as presented by @gian-paolo.
Otherwise, if these conditions are well established, and are kind of "solid rules" that will never change, consider my last code snippet.
add a comment |
up vote
5
down vote
It's easy to notice that first two scenarios are similar - they share most of the conditions. If you want to select in which scenario you are at the moment, you could write it like this (it's a modified @gian-paolo's solution):
bool valid = false;
if(bValue1 && bValue2 && bValue3)
{
if (bValue4)
valid = true; //scenario 1
else if (!bValue4)
valid = true; //scenario 2
}
else if (bValue1 && !bValue2 && !bValue3 && !bValue4)
valid = true; //scenario 3
Going further, you can notice, that first boolean needs to be always true, which is an entry condition, so you can end up with:
bool valid = false;
if(bValue1)
{
if(bValue2 && bValue3)
{
if (bValue4)
valid = true; //scenario 1
else if (!bValue4)
valid = true; //scenario 2
}
else if (!bValue2 && !bValue3 && !bValue4)
valid = true; //scenario 3
}
Even more, you can now clearly see, that bValue2 and bValue3 are somewhat connected - you could extract their state to some external functions or variables with more appropriate name (this is not always easy or appropriate though):
bool valid = false;
if(bValue1)
{
bool bValue1and2 = bValue1 && bValue2;
bool notBValue1and2 = !bValue2 && !bValue3;
if(bValue1and2)
{
if (bValue4)
valid = true; //scenario 1
else if (!bValue4)
valid = true; //scenario 2
}
else if (notBValue1and2 && !bValue4)
valid = true; //scenario 3
}
Doing it this way have some advantages and disadvantages:
- conditions are smaller, so it's easier to reason about them,
- it's easier to do nice renaming to make these conditions more understandable,
- but, they require to understand the scope,
- moreover it's more rigid
If you predict that there will be changes to the above logic, you should use more straightforward approach as presented by @gian-paolo.
Otherwise, if these conditions are well established, and are kind of "solid rules" that will never change, consider my last code snippet.
add a comment |
up vote
5
down vote
up vote
5
down vote
It's easy to notice that first two scenarios are similar - they share most of the conditions. If you want to select in which scenario you are at the moment, you could write it like this (it's a modified @gian-paolo's solution):
bool valid = false;
if(bValue1 && bValue2 && bValue3)
{
if (bValue4)
valid = true; //scenario 1
else if (!bValue4)
valid = true; //scenario 2
}
else if (bValue1 && !bValue2 && !bValue3 && !bValue4)
valid = true; //scenario 3
Going further, you can notice, that first boolean needs to be always true, which is an entry condition, so you can end up with:
bool valid = false;
if(bValue1)
{
if(bValue2 && bValue3)
{
if (bValue4)
valid = true; //scenario 1
else if (!bValue4)
valid = true; //scenario 2
}
else if (!bValue2 && !bValue3 && !bValue4)
valid = true; //scenario 3
}
Even more, you can now clearly see, that bValue2 and bValue3 are somewhat connected - you could extract their state to some external functions or variables with more appropriate name (this is not always easy or appropriate though):
bool valid = false;
if(bValue1)
{
bool bValue1and2 = bValue1 && bValue2;
bool notBValue1and2 = !bValue2 && !bValue3;
if(bValue1and2)
{
if (bValue4)
valid = true; //scenario 1
else if (!bValue4)
valid = true; //scenario 2
}
else if (notBValue1and2 && !bValue4)
valid = true; //scenario 3
}
Doing it this way have some advantages and disadvantages:
- conditions are smaller, so it's easier to reason about them,
- it's easier to do nice renaming to make these conditions more understandable,
- but, they require to understand the scope,
- moreover it's more rigid
If you predict that there will be changes to the above logic, you should use more straightforward approach as presented by @gian-paolo.
Otherwise, if these conditions are well established, and are kind of "solid rules" that will never change, consider my last code snippet.
It's easy to notice that first two scenarios are similar - they share most of the conditions. If you want to select in which scenario you are at the moment, you could write it like this (it's a modified @gian-paolo's solution):
bool valid = false;
if(bValue1 && bValue2 && bValue3)
{
if (bValue4)
valid = true; //scenario 1
else if (!bValue4)
valid = true; //scenario 2
}
else if (bValue1 && !bValue2 && !bValue3 && !bValue4)
valid = true; //scenario 3
Going further, you can notice, that first boolean needs to be always true, which is an entry condition, so you can end up with:
bool valid = false;
if(bValue1)
{
if(bValue2 && bValue3)
{
if (bValue4)
valid = true; //scenario 1
else if (!bValue4)
valid = true; //scenario 2
}
else if (!bValue2 && !bValue3 && !bValue4)
valid = true; //scenario 3
}
Even more, you can now clearly see, that bValue2 and bValue3 are somewhat connected - you could extract their state to some external functions or variables with more appropriate name (this is not always easy or appropriate though):
bool valid = false;
if(bValue1)
{
bool bValue1and2 = bValue1 && bValue2;
bool notBValue1and2 = !bValue2 && !bValue3;
if(bValue1and2)
{
if (bValue4)
valid = true; //scenario 1
else if (!bValue4)
valid = true; //scenario 2
}
else if (notBValue1and2 && !bValue4)
valid = true; //scenario 3
}
Doing it this way have some advantages and disadvantages:
- conditions are smaller, so it's easier to reason about them,
- it's easier to do nice renaming to make these conditions more understandable,
- but, they require to understand the scope,
- moreover it's more rigid
If you predict that there will be changes to the above logic, you should use more straightforward approach as presented by @gian-paolo.
Otherwise, if these conditions are well established, and are kind of "solid rules" that will never change, consider my last code snippet.
answered Dec 3 at 11:37
Michał Łoś
346210
346210
add a comment |
add a comment |
up vote
5
down vote
Consider translating your tables as directly as possible into your program. Drive the program based off the table, instead of mimicing it with logic.
template<class T0>
auto is_any_of( T0 const& t0, std::initializer_list<T0> il ) {
for (auto&& x:il)
if (x==t0) return true;
return false;
}
now
if (is_any_of(
std::make_tuple(bValue1, bValue2, bValue3, bValue4),
{
{true, true, true, true},
{true, true, true, false},
{true, false, false, false}
}
))
this directly as possible encodes your truth table into the compiler.
Live example.
You could also use std::any_of
directly:
using entry = std::array<bool, 4>;
constexpr entry acceptable =
{
{true, true, true, true},
{true, true, true, false},
{true, false, false, false}
};
if (std::any_of( begin(acceptable), end(acceptable), [&](auto&&x){
return entry{bValue1, bValue2, bValue3, bValue4} == x;
}) {
}
the compiler can inline the code, and eliminate any iteration and build its own logic for you. Meanwhile, your code reflects exactly how you concieved of the problem.
The first version is so easy to read and so maintenable, I really like it. The second one is harder to read, at least for me, and requires a c++ skill level maybe over the average, surely over my one. Not something everyone is able to write. Just learned somethin new, thanks
– Gian Paolo
2 days ago
Interesting alternative. 👍
– Andrew Truckle
yesterday
add a comment |
up vote
5
down vote
Consider translating your tables as directly as possible into your program. Drive the program based off the table, instead of mimicing it with logic.
template<class T0>
auto is_any_of( T0 const& t0, std::initializer_list<T0> il ) {
for (auto&& x:il)
if (x==t0) return true;
return false;
}
now
if (is_any_of(
std::make_tuple(bValue1, bValue2, bValue3, bValue4),
{
{true, true, true, true},
{true, true, true, false},
{true, false, false, false}
}
))
this directly as possible encodes your truth table into the compiler.
Live example.
You could also use std::any_of
directly:
using entry = std::array<bool, 4>;
constexpr entry acceptable =
{
{true, true, true, true},
{true, true, true, false},
{true, false, false, false}
};
if (std::any_of( begin(acceptable), end(acceptable), [&](auto&&x){
return entry{bValue1, bValue2, bValue3, bValue4} == x;
}) {
}
the compiler can inline the code, and eliminate any iteration and build its own logic for you. Meanwhile, your code reflects exactly how you concieved of the problem.
The first version is so easy to read and so maintenable, I really like it. The second one is harder to read, at least for me, and requires a c++ skill level maybe over the average, surely over my one. Not something everyone is able to write. Just learned somethin new, thanks
– Gian Paolo
2 days ago
Interesting alternative. 👍
– Andrew Truckle
yesterday
add a comment |
up vote
5
down vote
up vote
5
down vote
Consider translating your tables as directly as possible into your program. Drive the program based off the table, instead of mimicing it with logic.
template<class T0>
auto is_any_of( T0 const& t0, std::initializer_list<T0> il ) {
for (auto&& x:il)
if (x==t0) return true;
return false;
}
now
if (is_any_of(
std::make_tuple(bValue1, bValue2, bValue3, bValue4),
{
{true, true, true, true},
{true, true, true, false},
{true, false, false, false}
}
))
this directly as possible encodes your truth table into the compiler.
Live example.
You could also use std::any_of
directly:
using entry = std::array<bool, 4>;
constexpr entry acceptable =
{
{true, true, true, true},
{true, true, true, false},
{true, false, false, false}
};
if (std::any_of( begin(acceptable), end(acceptable), [&](auto&&x){
return entry{bValue1, bValue2, bValue3, bValue4} == x;
}) {
}
the compiler can inline the code, and eliminate any iteration and build its own logic for you. Meanwhile, your code reflects exactly how you concieved of the problem.
Consider translating your tables as directly as possible into your program. Drive the program based off the table, instead of mimicing it with logic.
template<class T0>
auto is_any_of( T0 const& t0, std::initializer_list<T0> il ) {
for (auto&& x:il)
if (x==t0) return true;
return false;
}
now
if (is_any_of(
std::make_tuple(bValue1, bValue2, bValue3, bValue4),
{
{true, true, true, true},
{true, true, true, false},
{true, false, false, false}
}
))
this directly as possible encodes your truth table into the compiler.
Live example.
You could also use std::any_of
directly:
using entry = std::array<bool, 4>;
constexpr entry acceptable =
{
{true, true, true, true},
{true, true, true, false},
{true, false, false, false}
};
if (std::any_of( begin(acceptable), end(acceptable), [&](auto&&x){
return entry{bValue1, bValue2, bValue3, bValue4} == x;
}) {
}
the compiler can inline the code, and eliminate any iteration and build its own logic for you. Meanwhile, your code reflects exactly how you concieved of the problem.
edited 2 days ago
answered 2 days ago
Yakk - Adam Nevraumont
180k19187367
180k19187367
The first version is so easy to read and so maintenable, I really like it. The second one is harder to read, at least for me, and requires a c++ skill level maybe over the average, surely over my one. Not something everyone is able to write. Just learned somethin new, thanks
– Gian Paolo
2 days ago
Interesting alternative. 👍
– Andrew Truckle
yesterday
add a comment |
The first version is so easy to read and so maintenable, I really like it. The second one is harder to read, at least for me, and requires a c++ skill level maybe over the average, surely over my one. Not something everyone is able to write. Just learned somethin new, thanks
– Gian Paolo
2 days ago
Interesting alternative. 👍
– Andrew Truckle
yesterday
The first version is so easy to read and so maintenable, I really like it. The second one is harder to read, at least for me, and requires a c++ skill level maybe over the average, surely over my one. Not something everyone is able to write. Just learned somethin new, thanks
– Gian Paolo
2 days ago
The first version is so easy to read and so maintenable, I really like it. The second one is harder to read, at least for me, and requires a c++ skill level maybe over the average, surely over my one. Not something everyone is able to write. Just learned somethin new, thanks
– Gian Paolo
2 days ago
Interesting alternative. 👍
– Andrew Truckle
yesterday
Interesting alternative. 👍
– Andrew Truckle
yesterday
add a comment |
up vote
3
down vote
I would also use shortcut variables for clarity. As noted earlier scenario 1 equals to scenario 2, because the value of bValue4 doesn't influence the truth of those two scenarios.
bool MAJORLY_TRUE=bValue1 && bValue2 && bValue3
bool MAJORLY_FALSE=!(bValue2 || bValue3 || bValue4)
then your expression beomes:
if (MAJORLY_TRUE || (bValue1 && MAJORLY_FALSE))
{
// do something
}
else
{
// There is some error
}
Giving meaningful names to MAJORTRUE and MAJORFALSE variables (as well as actually to bValue* vars) would help a lot with readability and maintenance.
add a comment |
up vote
3
down vote
I would also use shortcut variables for clarity. As noted earlier scenario 1 equals to scenario 2, because the value of bValue4 doesn't influence the truth of those two scenarios.
bool MAJORLY_TRUE=bValue1 && bValue2 && bValue3
bool MAJORLY_FALSE=!(bValue2 || bValue3 || bValue4)
then your expression beomes:
if (MAJORLY_TRUE || (bValue1 && MAJORLY_FALSE))
{
// do something
}
else
{
// There is some error
}
Giving meaningful names to MAJORTRUE and MAJORFALSE variables (as well as actually to bValue* vars) would help a lot with readability and maintenance.
add a comment |
up vote
3
down vote
up vote
3
down vote
I would also use shortcut variables for clarity. As noted earlier scenario 1 equals to scenario 2, because the value of bValue4 doesn't influence the truth of those two scenarios.
bool MAJORLY_TRUE=bValue1 && bValue2 && bValue3
bool MAJORLY_FALSE=!(bValue2 || bValue3 || bValue4)
then your expression beomes:
if (MAJORLY_TRUE || (bValue1 && MAJORLY_FALSE))
{
// do something
}
else
{
// There is some error
}
Giving meaningful names to MAJORTRUE and MAJORFALSE variables (as well as actually to bValue* vars) would help a lot with readability and maintenance.
I would also use shortcut variables for clarity. As noted earlier scenario 1 equals to scenario 2, because the value of bValue4 doesn't influence the truth of those two scenarios.
bool MAJORLY_TRUE=bValue1 && bValue2 && bValue3
bool MAJORLY_FALSE=!(bValue2 || bValue3 || bValue4)
then your expression beomes:
if (MAJORLY_TRUE || (bValue1 && MAJORLY_FALSE))
{
// do something
}
else
{
// There is some error
}
Giving meaningful names to MAJORTRUE and MAJORFALSE variables (as well as actually to bValue* vars) would help a lot with readability and maintenance.
answered Dec 3 at 11:59
Gnudiff
3,24111721
3,24111721
add a comment |
add a comment |
up vote
3
down vote
As suggested by mch, you could do:
if(!((bValue1 && bValue2 && bValue3) ||
(bValue1 && !bValue2 && !bValue3 && !bValue4))
)
where the first line covers the two first good cases, and the second line covers the last one.
Live Demo, where I played around and it passes your cases.
add a comment |
up vote
3
down vote
As suggested by mch, you could do:
if(!((bValue1 && bValue2 && bValue3) ||
(bValue1 && !bValue2 && !bValue3 && !bValue4))
)
where the first line covers the two first good cases, and the second line covers the last one.
Live Demo, where I played around and it passes your cases.
add a comment |
up vote
3
down vote
up vote
3
down vote
As suggested by mch, you could do:
if(!((bValue1 && bValue2 && bValue3) ||
(bValue1 && !bValue2 && !bValue3 && !bValue4))
)
where the first line covers the two first good cases, and the second line covers the last one.
Live Demo, where I played around and it passes your cases.
As suggested by mch, you could do:
if(!((bValue1 && bValue2 && bValue3) ||
(bValue1 && !bValue2 && !bValue3 && !bValue4))
)
where the first line covers the two first good cases, and the second line covers the last one.
Live Demo, where I played around and it passes your cases.
edited Dec 3 at 12:43
answered Dec 3 at 10:29
gsamaras
49.1k2398179
49.1k2398179
add a comment |
add a comment |
up vote
3
down vote
Focus on readability of the problem, not the specific "if" statement.
While this will produce more lines of code, and some may consider it either overkill or unnecessary. I'd suggest that abstracting your scenarios from the specific booleans is the best way to maintain readability.
By splitting things into classes (feel free to just use functions, or whatever other tool you prefer) with understandable names - we can much more easily show the meanings behind each scenario. More importantly, in a system with many moving parts - it is easier to maintain and join into your existing systems (again, despite how much extra code is involed).
#include <iostream>
#include <vector>
using namespace std;
// These values would likely not come from a single struct in real life
// Instead, they may be references to other booleans in other systems
struct Values
{
bool bValue1; // These would be given better names in reality
bool bValue2; // e.g. bDidTheCarCatchFire
bool bValue3; // and bDidTheWindshieldFallOff
bool bValue4;
};
class Scenario
{
public:
Scenario(Values& values)
: mValues(values) {}
virtual operator bool() = 0;
protected:
Values& mValues;
};
// Names as examples of things that describe your "scenarios" more effectively
class Scenario1_TheCarWasNotDamagedAtAll : public Scenario
{
public:
Scenario1_TheCarWasNotDamagedAtAll(Values& values) : Scenario(values) {}
virtual operator bool()
{
return mValues.bValue1
&& mValues.bValue2
&& mValues.bValue3
&& mValues.bValue4;
}
};
class Scenario2_TheCarBreaksDownButDidntGoOnFire : public Scenario
{
public:
Scenario2_TheCarBreaksDownButDidntGoOnFire(Values& values) : Scenario(values) {}
virtual operator bool()
{
return mValues.bValue1
&& mValues.bValue2
&& mValues.bValue3
&& !mValues.bValue4;
}
};
class Scenario3_TheCarWasCompletelyWreckedAndFireEverywhere : public Scenario
{
public:
Scenario3_TheCarWasCompletelyWreckedAndFireEverywhere(Values& values) : Scenario(values) {}
virtual operator bool()
{
return mValues.bValue1
&& !mValues.bValue2
&& !mValues.bValue3
&& !mValues.bValue4;
}
};
Scenario* findMatchingScenario(std::vector<Scenario*>& scenarios)
{
for(std::vector<Scenario*>::iterator it = scenarios.begin(); it != scenarios.end(); it++)
{
if (**it)
{
return *it;
}
}
return NULL;
}
int main() {
Values values = {true, true, true, true};
std::vector<Scenario*> scenarios = {
new Scenario1_TheCarWasNotDamagedAtAll(values),
new Scenario2_TheCarBreaksDownButDidntGoOnFire(values),
new Scenario3_TheCarWasCompletelyWreckedAndFireEverywhere(values)
};
Scenario* matchingScenario = findMatchingScenario(scenarios);
if(matchingScenario)
{
std::cout << matchingScenario << " was a match" << std::endl;
}
else
{
std::cout << "No match" << std::endl;
}
// your code goes here
return 0;
}
5
At some point, verbosity starts to harm readability. I think this goes too far.
– JollyJoker
Dec 3 at 13:01
2
@JollyJoker I do actually agree in this specific situation - however, my gut feeling from the way OP has named everything extremely generically, is that their "real" code is likely a lot more complex than the example they've given. Really, I just wanted to put this alternative out there, as it's how I'd structure it for something far more complex/involved. But you're right - for OPs specific example, it is overly verbose and makes matters worse.
– Bilkokuya
Dec 3 at 13:30
add a comment |
up vote
3
down vote
Focus on readability of the problem, not the specific "if" statement.
While this will produce more lines of code, and some may consider it either overkill or unnecessary. I'd suggest that abstracting your scenarios from the specific booleans is the best way to maintain readability.
By splitting things into classes (feel free to just use functions, or whatever other tool you prefer) with understandable names - we can much more easily show the meanings behind each scenario. More importantly, in a system with many moving parts - it is easier to maintain and join into your existing systems (again, despite how much extra code is involed).
#include <iostream>
#include <vector>
using namespace std;
// These values would likely not come from a single struct in real life
// Instead, they may be references to other booleans in other systems
struct Values
{
bool bValue1; // These would be given better names in reality
bool bValue2; // e.g. bDidTheCarCatchFire
bool bValue3; // and bDidTheWindshieldFallOff
bool bValue4;
};
class Scenario
{
public:
Scenario(Values& values)
: mValues(values) {}
virtual operator bool() = 0;
protected:
Values& mValues;
};
// Names as examples of things that describe your "scenarios" more effectively
class Scenario1_TheCarWasNotDamagedAtAll : public Scenario
{
public:
Scenario1_TheCarWasNotDamagedAtAll(Values& values) : Scenario(values) {}
virtual operator bool()
{
return mValues.bValue1
&& mValues.bValue2
&& mValues.bValue3
&& mValues.bValue4;
}
};
class Scenario2_TheCarBreaksDownButDidntGoOnFire : public Scenario
{
public:
Scenario2_TheCarBreaksDownButDidntGoOnFire(Values& values) : Scenario(values) {}
virtual operator bool()
{
return mValues.bValue1
&& mValues.bValue2
&& mValues.bValue3
&& !mValues.bValue4;
}
};
class Scenario3_TheCarWasCompletelyWreckedAndFireEverywhere : public Scenario
{
public:
Scenario3_TheCarWasCompletelyWreckedAndFireEverywhere(Values& values) : Scenario(values) {}
virtual operator bool()
{
return mValues.bValue1
&& !mValues.bValue2
&& !mValues.bValue3
&& !mValues.bValue4;
}
};
Scenario* findMatchingScenario(std::vector<Scenario*>& scenarios)
{
for(std::vector<Scenario*>::iterator it = scenarios.begin(); it != scenarios.end(); it++)
{
if (**it)
{
return *it;
}
}
return NULL;
}
int main() {
Values values = {true, true, true, true};
std::vector<Scenario*> scenarios = {
new Scenario1_TheCarWasNotDamagedAtAll(values),
new Scenario2_TheCarBreaksDownButDidntGoOnFire(values),
new Scenario3_TheCarWasCompletelyWreckedAndFireEverywhere(values)
};
Scenario* matchingScenario = findMatchingScenario(scenarios);
if(matchingScenario)
{
std::cout << matchingScenario << " was a match" << std::endl;
}
else
{
std::cout << "No match" << std::endl;
}
// your code goes here
return 0;
}
5
At some point, verbosity starts to harm readability. I think this goes too far.
– JollyJoker
Dec 3 at 13:01
2
@JollyJoker I do actually agree in this specific situation - however, my gut feeling from the way OP has named everything extremely generically, is that their "real" code is likely a lot more complex than the example they've given. Really, I just wanted to put this alternative out there, as it's how I'd structure it for something far more complex/involved. But you're right - for OPs specific example, it is overly verbose and makes matters worse.
– Bilkokuya
Dec 3 at 13:30
add a comment |
up vote
3
down vote
up vote
3
down vote
Focus on readability of the problem, not the specific "if" statement.
While this will produce more lines of code, and some may consider it either overkill or unnecessary. I'd suggest that abstracting your scenarios from the specific booleans is the best way to maintain readability.
By splitting things into classes (feel free to just use functions, or whatever other tool you prefer) with understandable names - we can much more easily show the meanings behind each scenario. More importantly, in a system with many moving parts - it is easier to maintain and join into your existing systems (again, despite how much extra code is involed).
#include <iostream>
#include <vector>
using namespace std;
// These values would likely not come from a single struct in real life
// Instead, they may be references to other booleans in other systems
struct Values
{
bool bValue1; // These would be given better names in reality
bool bValue2; // e.g. bDidTheCarCatchFire
bool bValue3; // and bDidTheWindshieldFallOff
bool bValue4;
};
class Scenario
{
public:
Scenario(Values& values)
: mValues(values) {}
virtual operator bool() = 0;
protected:
Values& mValues;
};
// Names as examples of things that describe your "scenarios" more effectively
class Scenario1_TheCarWasNotDamagedAtAll : public Scenario
{
public:
Scenario1_TheCarWasNotDamagedAtAll(Values& values) : Scenario(values) {}
virtual operator bool()
{
return mValues.bValue1
&& mValues.bValue2
&& mValues.bValue3
&& mValues.bValue4;
}
};
class Scenario2_TheCarBreaksDownButDidntGoOnFire : public Scenario
{
public:
Scenario2_TheCarBreaksDownButDidntGoOnFire(Values& values) : Scenario(values) {}
virtual operator bool()
{
return mValues.bValue1
&& mValues.bValue2
&& mValues.bValue3
&& !mValues.bValue4;
}
};
class Scenario3_TheCarWasCompletelyWreckedAndFireEverywhere : public Scenario
{
public:
Scenario3_TheCarWasCompletelyWreckedAndFireEverywhere(Values& values) : Scenario(values) {}
virtual operator bool()
{
return mValues.bValue1
&& !mValues.bValue2
&& !mValues.bValue3
&& !mValues.bValue4;
}
};
Scenario* findMatchingScenario(std::vector<Scenario*>& scenarios)
{
for(std::vector<Scenario*>::iterator it = scenarios.begin(); it != scenarios.end(); it++)
{
if (**it)
{
return *it;
}
}
return NULL;
}
int main() {
Values values = {true, true, true, true};
std::vector<Scenario*> scenarios = {
new Scenario1_TheCarWasNotDamagedAtAll(values),
new Scenario2_TheCarBreaksDownButDidntGoOnFire(values),
new Scenario3_TheCarWasCompletelyWreckedAndFireEverywhere(values)
};
Scenario* matchingScenario = findMatchingScenario(scenarios);
if(matchingScenario)
{
std::cout << matchingScenario << " was a match" << std::endl;
}
else
{
std::cout << "No match" << std::endl;
}
// your code goes here
return 0;
}
Focus on readability of the problem, not the specific "if" statement.
While this will produce more lines of code, and some may consider it either overkill or unnecessary. I'd suggest that abstracting your scenarios from the specific booleans is the best way to maintain readability.
By splitting things into classes (feel free to just use functions, or whatever other tool you prefer) with understandable names - we can much more easily show the meanings behind each scenario. More importantly, in a system with many moving parts - it is easier to maintain and join into your existing systems (again, despite how much extra code is involed).
#include <iostream>
#include <vector>
using namespace std;
// These values would likely not come from a single struct in real life
// Instead, they may be references to other booleans in other systems
struct Values
{
bool bValue1; // These would be given better names in reality
bool bValue2; // e.g. bDidTheCarCatchFire
bool bValue3; // and bDidTheWindshieldFallOff
bool bValue4;
};
class Scenario
{
public:
Scenario(Values& values)
: mValues(values) {}
virtual operator bool() = 0;
protected:
Values& mValues;
};
// Names as examples of things that describe your "scenarios" more effectively
class Scenario1_TheCarWasNotDamagedAtAll : public Scenario
{
public:
Scenario1_TheCarWasNotDamagedAtAll(Values& values) : Scenario(values) {}
virtual operator bool()
{
return mValues.bValue1
&& mValues.bValue2
&& mValues.bValue3
&& mValues.bValue4;
}
};
class Scenario2_TheCarBreaksDownButDidntGoOnFire : public Scenario
{
public:
Scenario2_TheCarBreaksDownButDidntGoOnFire(Values& values) : Scenario(values) {}
virtual operator bool()
{
return mValues.bValue1
&& mValues.bValue2
&& mValues.bValue3
&& !mValues.bValue4;
}
};
class Scenario3_TheCarWasCompletelyWreckedAndFireEverywhere : public Scenario
{
public:
Scenario3_TheCarWasCompletelyWreckedAndFireEverywhere(Values& values) : Scenario(values) {}
virtual operator bool()
{
return mValues.bValue1
&& !mValues.bValue2
&& !mValues.bValue3
&& !mValues.bValue4;
}
};
Scenario* findMatchingScenario(std::vector<Scenario*>& scenarios)
{
for(std::vector<Scenario*>::iterator it = scenarios.begin(); it != scenarios.end(); it++)
{
if (**it)
{
return *it;
}
}
return NULL;
}
int main() {
Values values = {true, true, true, true};
std::vector<Scenario*> scenarios = {
new Scenario1_TheCarWasNotDamagedAtAll(values),
new Scenario2_TheCarBreaksDownButDidntGoOnFire(values),
new Scenario3_TheCarWasCompletelyWreckedAndFireEverywhere(values)
};
Scenario* matchingScenario = findMatchingScenario(scenarios);
if(matchingScenario)
{
std::cout << matchingScenario << " was a match" << std::endl;
}
else
{
std::cout << "No match" << std::endl;
}
// your code goes here
return 0;
}
answered Dec 3 at 12:54
Bilkokuya
750616
750616
5
At some point, verbosity starts to harm readability. I think this goes too far.
– JollyJoker
Dec 3 at 13:01
2
@JollyJoker I do actually agree in this specific situation - however, my gut feeling from the way OP has named everything extremely generically, is that their "real" code is likely a lot more complex than the example they've given. Really, I just wanted to put this alternative out there, as it's how I'd structure it for something far more complex/involved. But you're right - for OPs specific example, it is overly verbose and makes matters worse.
– Bilkokuya
Dec 3 at 13:30
add a comment |
5
At some point, verbosity starts to harm readability. I think this goes too far.
– JollyJoker
Dec 3 at 13:01
2
@JollyJoker I do actually agree in this specific situation - however, my gut feeling from the way OP has named everything extremely generically, is that their "real" code is likely a lot more complex than the example they've given. Really, I just wanted to put this alternative out there, as it's how I'd structure it for something far more complex/involved. But you're right - for OPs specific example, it is overly verbose and makes matters worse.
– Bilkokuya
Dec 3 at 13:30
5
5
At some point, verbosity starts to harm readability. I think this goes too far.
– JollyJoker
Dec 3 at 13:01
At some point, verbosity starts to harm readability. I think this goes too far.
– JollyJoker
Dec 3 at 13:01
2
2
@JollyJoker I do actually agree in this specific situation - however, my gut feeling from the way OP has named everything extremely generically, is that their "real" code is likely a lot more complex than the example they've given. Really, I just wanted to put this alternative out there, as it's how I'd structure it for something far more complex/involved. But you're right - for OPs specific example, it is overly verbose and makes matters worse.
– Bilkokuya
Dec 3 at 13:30
@JollyJoker I do actually agree in this specific situation - however, my gut feeling from the way OP has named everything extremely generically, is that their "real" code is likely a lot more complex than the example they've given. Really, I just wanted to put this alternative out there, as it's how I'd structure it for something far more complex/involved. But you're right - for OPs specific example, it is overly verbose and makes matters worse.
– Bilkokuya
Dec 3 at 13:30
add a comment |
up vote
3
down vote
A slight variation on @GianPaolo's fine answer, which some may find easier to read:
bool any_of_three_scenarios(bool v1, bool v2, bool v3, bool v4)
{
return (v1 && v2 && v3 && v4) // scenario 1
|| (v1 && v2 && v3 && !v4) // scenario 2
|| (v1 && !v2 && !v3 && !v4); // scenario 3
}
if (any_of_three_scenarios(bValue1,bValue2,bValue3,bValue4))
{
// ...
}
add a comment |
up vote
3
down vote
A slight variation on @GianPaolo's fine answer, which some may find easier to read:
bool any_of_three_scenarios(bool v1, bool v2, bool v3, bool v4)
{
return (v1 && v2 && v3 && v4) // scenario 1
|| (v1 && v2 && v3 && !v4) // scenario 2
|| (v1 && !v2 && !v3 && !v4); // scenario 3
}
if (any_of_three_scenarios(bValue1,bValue2,bValue3,bValue4))
{
// ...
}
add a comment |
up vote
3
down vote
up vote
3
down vote
A slight variation on @GianPaolo's fine answer, which some may find easier to read:
bool any_of_three_scenarios(bool v1, bool v2, bool v3, bool v4)
{
return (v1 && v2 && v3 && v4) // scenario 1
|| (v1 && v2 && v3 && !v4) // scenario 2
|| (v1 && !v2 && !v3 && !v4); // scenario 3
}
if (any_of_three_scenarios(bValue1,bValue2,bValue3,bValue4))
{
// ...
}
A slight variation on @GianPaolo's fine answer, which some may find easier to read:
bool any_of_three_scenarios(bool v1, bool v2, bool v3, bool v4)
{
return (v1 && v2 && v3 && v4) // scenario 1
|| (v1 && v2 && v3 && !v4) // scenario 2
|| (v1 && !v2 && !v3 && !v4); // scenario 3
}
if (any_of_three_scenarios(bValue1,bValue2,bValue3,bValue4))
{
// ...
}
answered Dec 3 at 22:04
Matt
15.1k13447
15.1k13447
add a comment |
add a comment |
up vote
3
down vote
It depends on what they represent.
For example if 1 is a key, and 2 and 3 are two people who must agree (except if they agree on NOT
they need a third person - 4 - to confirm) the most readable might be:
1 &&
(
(2 && 3)
||
((!2 && !3) && !4)
)
by popular request:
Key &&
(
(Alice && Bob)
||
((!Alice && !Bob) && !Charlie)
)
2
You might be right, but using numbers to illustrate your point detracts from your answer. Try using descriptive names.
– jxh
Dec 3 at 22:45
1
@jxh Those are the numbers OP used. I just removed thebValue
.
– ispiro
Dec 3 at 23:26
@jxh I hope it's better now.
– ispiro
yesterday
add a comment |
up vote
3
down vote
It depends on what they represent.
For example if 1 is a key, and 2 and 3 are two people who must agree (except if they agree on NOT
they need a third person - 4 - to confirm) the most readable might be:
1 &&
(
(2 && 3)
||
((!2 && !3) && !4)
)
by popular request:
Key &&
(
(Alice && Bob)
||
((!Alice && !Bob) && !Charlie)
)
2
You might be right, but using numbers to illustrate your point detracts from your answer. Try using descriptive names.
– jxh
Dec 3 at 22:45
1
@jxh Those are the numbers OP used. I just removed thebValue
.
– ispiro
Dec 3 at 23:26
@jxh I hope it's better now.
– ispiro
yesterday
add a comment |
up vote
3
down vote
up vote
3
down vote
It depends on what they represent.
For example if 1 is a key, and 2 and 3 are two people who must agree (except if they agree on NOT
they need a third person - 4 - to confirm) the most readable might be:
1 &&
(
(2 && 3)
||
((!2 && !3) && !4)
)
by popular request:
Key &&
(
(Alice && Bob)
||
((!Alice && !Bob) && !Charlie)
)
It depends on what they represent.
For example if 1 is a key, and 2 and 3 are two people who must agree (except if they agree on NOT
they need a third person - 4 - to confirm) the most readable might be:
1 &&
(
(2 && 3)
||
((!2 && !3) && !4)
)
by popular request:
Key &&
(
(Alice && Bob)
||
((!Alice && !Bob) && !Charlie)
)
edited yesterday
answered Dec 3 at 21:58
ispiro
12.8k1979178
12.8k1979178
2
You might be right, but using numbers to illustrate your point detracts from your answer. Try using descriptive names.
– jxh
Dec 3 at 22:45
1
@jxh Those are the numbers OP used. I just removed thebValue
.
– ispiro
Dec 3 at 23:26
@jxh I hope it's better now.
– ispiro
yesterday
add a comment |
2
You might be right, but using numbers to illustrate your point detracts from your answer. Try using descriptive names.
– jxh
Dec 3 at 22:45
1
@jxh Those are the numbers OP used. I just removed thebValue
.
– ispiro
Dec 3 at 23:26
@jxh I hope it's better now.
– ispiro
yesterday
2
2
You might be right, but using numbers to illustrate your point detracts from your answer. Try using descriptive names.
– jxh
Dec 3 at 22:45
You might be right, but using numbers to illustrate your point detracts from your answer. Try using descriptive names.
– jxh
Dec 3 at 22:45
1
1
@jxh Those are the numbers OP used. I just removed the
bValue
.– ispiro
Dec 3 at 23:26
@jxh Those are the numbers OP used. I just removed the
bValue
.– ispiro
Dec 3 at 23:26
@jxh I hope it's better now.
– ispiro
yesterday
@jxh I hope it's better now.
– ispiro
yesterday
add a comment |
up vote
3
down vote
Every answer is overly complex and difficult to read. The best solution to this is a switch()
statement. It is both readable and makes adding/modifying additional cases simple. Compilers are good at optimising switch()
statements too.
switch( (bValue4 << 3) | (bValue3 << 2) | (bValue2 << 1) | (bValue1) )
{
case 0b1111:
// scenario 1
break;
case 0b0111:
// scenario 2
break;
case 0b0001:
// scenario 3
break;
default:
// fault condition
break;
}
You can of course use constants and OR them together in the case
statements for even greater readability.
Being an old C-programmer, I'd define a "PackBools" macro and use that both for the "switch(PackBools(a,b,c,d))" and for the cases, eg either directly "case PackBools(true, true...)" or define them as local constants.e.g. "const unsigned int scenario1 = PackBools(true, true...);"
– Simon F
13 hours ago
add a comment |
up vote
3
down vote
Every answer is overly complex and difficult to read. The best solution to this is a switch()
statement. It is both readable and makes adding/modifying additional cases simple. Compilers are good at optimising switch()
statements too.
switch( (bValue4 << 3) | (bValue3 << 2) | (bValue2 << 1) | (bValue1) )
{
case 0b1111:
// scenario 1
break;
case 0b0111:
// scenario 2
break;
case 0b0001:
// scenario 3
break;
default:
// fault condition
break;
}
You can of course use constants and OR them together in the case
statements for even greater readability.
Being an old C-programmer, I'd define a "PackBools" macro and use that both for the "switch(PackBools(a,b,c,d))" and for the cases, eg either directly "case PackBools(true, true...)" or define them as local constants.e.g. "const unsigned int scenario1 = PackBools(true, true...);"
– Simon F
13 hours ago
add a comment |
up vote
3
down vote
up vote
3
down vote
Every answer is overly complex and difficult to read. The best solution to this is a switch()
statement. It is both readable and makes adding/modifying additional cases simple. Compilers are good at optimising switch()
statements too.
switch( (bValue4 << 3) | (bValue3 << 2) | (bValue2 << 1) | (bValue1) )
{
case 0b1111:
// scenario 1
break;
case 0b0111:
// scenario 2
break;
case 0b0001:
// scenario 3
break;
default:
// fault condition
break;
}
You can of course use constants and OR them together in the case
statements for even greater readability.
Every answer is overly complex and difficult to read. The best solution to this is a switch()
statement. It is both readable and makes adding/modifying additional cases simple. Compilers are good at optimising switch()
statements too.
switch( (bValue4 << 3) | (bValue3 << 2) | (bValue2 << 1) | (bValue1) )
{
case 0b1111:
// scenario 1
break;
case 0b0111:
// scenario 2
break;
case 0b0001:
// scenario 3
break;
default:
// fault condition
break;
}
You can of course use constants and OR them together in the case
statements for even greater readability.
edited yesterday
answered 2 days ago
shogged
1867
1867
Being an old C-programmer, I'd define a "PackBools" macro and use that both for the "switch(PackBools(a,b,c,d))" and for the cases, eg either directly "case PackBools(true, true...)" or define them as local constants.e.g. "const unsigned int scenario1 = PackBools(true, true...);"
– Simon F
13 hours ago
add a comment |
Being an old C-programmer, I'd define a "PackBools" macro and use that both for the "switch(PackBools(a,b,c,d))" and for the cases, eg either directly "case PackBools(true, true...)" or define them as local constants.e.g. "const unsigned int scenario1 = PackBools(true, true...);"
– Simon F
13 hours ago
Being an old C-programmer, I'd define a "PackBools" macro and use that both for the "switch(PackBools(a,b,c,d))" and for the cases, eg either directly "case PackBools(true, true...)" or define them as local constants.e.g. "const unsigned int scenario1 = PackBools(true, true...);"
– Simon F
13 hours ago
Being an old C-programmer, I'd define a "PackBools" macro and use that both for the "switch(PackBools(a,b,c,d))" and for the cases, eg either directly "case PackBools(true, true...)" or define them as local constants.e.g. "const unsigned int scenario1 = PackBools(true, true...);"
– Simon F
13 hours ago
add a comment |
up vote
2
down vote
I am denoting a, b, c, d for clarity, and A, B, C, D for complements
bValue1 = a (!A)
bValue2 = b (!B)
bValue3 = c (!C)
bValue4 = d (!D)
Equation
1 = abcd + abcD + aBCD
= a (bcd + bcD + BCD)
= a (bc + BCD)
= a (bcd + D (b ^C))
Use any equations that suits you.
add a comment |
up vote
2
down vote
I am denoting a, b, c, d for clarity, and A, B, C, D for complements
bValue1 = a (!A)
bValue2 = b (!B)
bValue3 = c (!C)
bValue4 = d (!D)
Equation
1 = abcd + abcD + aBCD
= a (bcd + bcD + BCD)
= a (bc + BCD)
= a (bcd + D (b ^C))
Use any equations that suits you.
add a comment |
up vote
2
down vote
up vote
2
down vote
I am denoting a, b, c, d for clarity, and A, B, C, D for complements
bValue1 = a (!A)
bValue2 = b (!B)
bValue3 = c (!C)
bValue4 = d (!D)
Equation
1 = abcd + abcD + aBCD
= a (bcd + bcD + BCD)
= a (bc + BCD)
= a (bcd + D (b ^C))
Use any equations that suits you.
I am denoting a, b, c, d for clarity, and A, B, C, D for complements
bValue1 = a (!A)
bValue2 = b (!B)
bValue3 = c (!C)
bValue4 = d (!D)
Equation
1 = abcd + abcD + aBCD
= a (bcd + bcD + BCD)
= a (bc + BCD)
= a (bcd + D (b ^C))
Use any equations that suits you.
answered Dec 3 at 10:42
yumoji
1,40211123
1,40211123
add a comment |
add a comment |
up vote
2
down vote
If (!bValue1 || (bValue2 != bValue3) || (!bValue4 && bValue2))
{
// you have a problem
}
- b1 must always be true
- b2 must always equal b3
- and b4 cannot be false
if b2 (and b3) are true
simple
New contributor
add a comment |
up vote
2
down vote
If (!bValue1 || (bValue2 != bValue3) || (!bValue4 && bValue2))
{
// you have a problem
}
- b1 must always be true
- b2 must always equal b3
- and b4 cannot be false
if b2 (and b3) are true
simple
New contributor
add a comment |
up vote
2
down vote
up vote
2
down vote
If (!bValue1 || (bValue2 != bValue3) || (!bValue4 && bValue2))
{
// you have a problem
}
- b1 must always be true
- b2 must always equal b3
- and b4 cannot be false
if b2 (and b3) are true
simple
New contributor
If (!bValue1 || (bValue2 != bValue3) || (!bValue4 && bValue2))
{
// you have a problem
}
- b1 must always be true
- b2 must always equal b3
- and b4 cannot be false
if b2 (and b3) are true
simple
New contributor
New contributor
answered 2 days ago
Owen Meyer
211
211
New contributor
New contributor
add a comment |
add a comment |
up vote
2
down vote
Doing bitwise operation looks very clean and understandable.
int bitwise = (bValue4 << 3) | (bValue3 << 2) | (bValue2 << 1) | (bValue1);
if (bitwise == 0b1111 || bitwise == 0b0111 || bitwise == 0b0001)
{
//satisfying condition
}
The bitwise comparison looks readable to me. The composition, on the other hand, looks artificial.
– xtofl
yesterday
add a comment |
up vote
2
down vote
Doing bitwise operation looks very clean and understandable.
int bitwise = (bValue4 << 3) | (bValue3 << 2) | (bValue2 << 1) | (bValue1);
if (bitwise == 0b1111 || bitwise == 0b0111 || bitwise == 0b0001)
{
//satisfying condition
}
The bitwise comparison looks readable to me. The composition, on the other hand, looks artificial.
– xtofl
yesterday
add a comment |
up vote
2
down vote
up vote
2
down vote
Doing bitwise operation looks very clean and understandable.
int bitwise = (bValue4 << 3) | (bValue3 << 2) | (bValue2 << 1) | (bValue1);
if (bitwise == 0b1111 || bitwise == 0b0111 || bitwise == 0b0001)
{
//satisfying condition
}
Doing bitwise operation looks very clean and understandable.
int bitwise = (bValue4 << 3) | (bValue3 << 2) | (bValue2 << 1) | (bValue1);
if (bitwise == 0b1111 || bitwise == 0b0111 || bitwise == 0b0001)
{
//satisfying condition
}
answered 2 days ago
Simonare
483211
483211
The bitwise comparison looks readable to me. The composition, on the other hand, looks artificial.
– xtofl
yesterday
add a comment |
The bitwise comparison looks readable to me. The composition, on the other hand, looks artificial.
– xtofl
yesterday
The bitwise comparison looks readable to me. The composition, on the other hand, looks artificial.
– xtofl
yesterday
The bitwise comparison looks readable to me. The composition, on the other hand, looks artificial.
– xtofl
yesterday
add a comment |
up vote
1
down vote
First, assuming you can only modify the scenario check, I would focus on readability and just wrap the check in a function so that you can just call if(ScenarioA())
.
Now, assuming you actually want/need to optimize this, I would recommend converting the tightly linked Booleans into constant integers, and using bit operators on them
public class Options {
public const bool A = 2; // 0001
public const bool B = 4; // 0010
public const bool C = 16;// 0100
public const bool D = 32;// 1000
//public const bool N = 2^n; (up to n=32)
}
...
public isScenario3(int options) {
int s3 = Options.A | Options.B | Options.C;
// for true if only s3 options are set
return options == s3;
// for true if s3 options are set
// return options & s3 == s3
}
This makes expressing the scenarios as easy as listing what is part of it, allows you to use a switch statement to jump to the right condition, and confuse fellow developers who have not seen this before. (C# RegexOptions uses this pattern for setting flags, I don't know if there is a c++ library example)
In actual fact I am not using four bool values but a DWORD with four embedded BOOLS. Too late to change it now. But thanks for your suggestion.
– Andrew Truckle
yesterday
add a comment |
up vote
1
down vote
First, assuming you can only modify the scenario check, I would focus on readability and just wrap the check in a function so that you can just call if(ScenarioA())
.
Now, assuming you actually want/need to optimize this, I would recommend converting the tightly linked Booleans into constant integers, and using bit operators on them
public class Options {
public const bool A = 2; // 0001
public const bool B = 4; // 0010
public const bool C = 16;// 0100
public const bool D = 32;// 1000
//public const bool N = 2^n; (up to n=32)
}
...
public isScenario3(int options) {
int s3 = Options.A | Options.B | Options.C;
// for true if only s3 options are set
return options == s3;
// for true if s3 options are set
// return options & s3 == s3
}
This makes expressing the scenarios as easy as listing what is part of it, allows you to use a switch statement to jump to the right condition, and confuse fellow developers who have not seen this before. (C# RegexOptions uses this pattern for setting flags, I don't know if there is a c++ library example)
In actual fact I am not using four bool values but a DWORD with four embedded BOOLS. Too late to change it now. But thanks for your suggestion.
– Andrew Truckle
yesterday
add a comment |
up vote
1
down vote
up vote
1
down vote
First, assuming you can only modify the scenario check, I would focus on readability and just wrap the check in a function so that you can just call if(ScenarioA())
.
Now, assuming you actually want/need to optimize this, I would recommend converting the tightly linked Booleans into constant integers, and using bit operators on them
public class Options {
public const bool A = 2; // 0001
public const bool B = 4; // 0010
public const bool C = 16;// 0100
public const bool D = 32;// 1000
//public const bool N = 2^n; (up to n=32)
}
...
public isScenario3(int options) {
int s3 = Options.A | Options.B | Options.C;
// for true if only s3 options are set
return options == s3;
// for true if s3 options are set
// return options & s3 == s3
}
This makes expressing the scenarios as easy as listing what is part of it, allows you to use a switch statement to jump to the right condition, and confuse fellow developers who have not seen this before. (C# RegexOptions uses this pattern for setting flags, I don't know if there is a c++ library example)
First, assuming you can only modify the scenario check, I would focus on readability and just wrap the check in a function so that you can just call if(ScenarioA())
.
Now, assuming you actually want/need to optimize this, I would recommend converting the tightly linked Booleans into constant integers, and using bit operators on them
public class Options {
public const bool A = 2; // 0001
public const bool B = 4; // 0010
public const bool C = 16;// 0100
public const bool D = 32;// 1000
//public const bool N = 2^n; (up to n=32)
}
...
public isScenario3(int options) {
int s3 = Options.A | Options.B | Options.C;
// for true if only s3 options are set
return options == s3;
// for true if s3 options are set
// return options & s3 == s3
}
This makes expressing the scenarios as easy as listing what is part of it, allows you to use a switch statement to jump to the right condition, and confuse fellow developers who have not seen this before. (C# RegexOptions uses this pattern for setting flags, I don't know if there is a c++ library example)
answered 2 days ago
Tezra
4,90821042
4,90821042
In actual fact I am not using four bool values but a DWORD with four embedded BOOLS. Too late to change it now. But thanks for your suggestion.
– Andrew Truckle
yesterday
add a comment |
In actual fact I am not using four bool values but a DWORD with four embedded BOOLS. Too late to change it now. But thanks for your suggestion.
– Andrew Truckle
yesterday
In actual fact I am not using four bool values but a DWORD with four embedded BOOLS. Too late to change it now. But thanks for your suggestion.
– Andrew Truckle
yesterday
In actual fact I am not using four bool values but a DWORD with four embedded BOOLS. Too late to change it now. But thanks for your suggestion.
– Andrew Truckle
yesterday
add a comment |
up vote
1
down vote
Nested if
s could be easier to read for some people. Here is my version
bool check(int bValue1, int bValue2, int bValue3, int bValue4)
{
if (bValue1)
{
if (bValue2)
{
// scenario 1-2
return bValue3;
}
else
{
// scenario 3
return !bValue3 && !bValue4;
}
}
return false;
}
Another interesting variation. Thank you.
– Andrew Truckle
yesterday
Personally, I'd usually avoid nesting if statements if possible. While this case is nice and readable, once new possibilities are added, the nesting can become very hard to read. But if the scenarios never change, it definitly is a nice and readable solution.
– Dnomyar96
16 hours ago
@Dnomyar96 i agree. I personally avoid nested ifs too. Sometimes if the logic is complicated, it is easier for me to understand the logic by breaking it down into the pieces. For example, once you enterbValue1
block, then you may treat everything in it as a new fresh page in your mental process. I bet the way of approaching to the problem may be very personal or even cultural thing.
– sardok
16 hours ago
add a comment |
up vote
1
down vote
Nested if
s could be easier to read for some people. Here is my version
bool check(int bValue1, int bValue2, int bValue3, int bValue4)
{
if (bValue1)
{
if (bValue2)
{
// scenario 1-2
return bValue3;
}
else
{
// scenario 3
return !bValue3 && !bValue4;
}
}
return false;
}
Another interesting variation. Thank you.
– Andrew Truckle
yesterday
Personally, I'd usually avoid nesting if statements if possible. While this case is nice and readable, once new possibilities are added, the nesting can become very hard to read. But if the scenarios never change, it definitly is a nice and readable solution.
– Dnomyar96
16 hours ago
@Dnomyar96 i agree. I personally avoid nested ifs too. Sometimes if the logic is complicated, it is easier for me to understand the logic by breaking it down into the pieces. For example, once you enterbValue1
block, then you may treat everything in it as a new fresh page in your mental process. I bet the way of approaching to the problem may be very personal or even cultural thing.
– sardok
16 hours ago
add a comment |
up vote
1
down vote
up vote
1
down vote
Nested if
s could be easier to read for some people. Here is my version
bool check(int bValue1, int bValue2, int bValue3, int bValue4)
{
if (bValue1)
{
if (bValue2)
{
// scenario 1-2
return bValue3;
}
else
{
// scenario 3
return !bValue3 && !bValue4;
}
}
return false;
}
Nested if
s could be easier to read for some people. Here is my version
bool check(int bValue1, int bValue2, int bValue3, int bValue4)
{
if (bValue1)
{
if (bValue2)
{
// scenario 1-2
return bValue3;
}
else
{
// scenario 3
return !bValue3 && !bValue4;
}
}
return false;
}
answered yesterday
sardok
6821514
6821514
Another interesting variation. Thank you.
– Andrew Truckle
yesterday
Personally, I'd usually avoid nesting if statements if possible. While this case is nice and readable, once new possibilities are added, the nesting can become very hard to read. But if the scenarios never change, it definitly is a nice and readable solution.
– Dnomyar96
16 hours ago
@Dnomyar96 i agree. I personally avoid nested ifs too. Sometimes if the logic is complicated, it is easier for me to understand the logic by breaking it down into the pieces. For example, once you enterbValue1
block, then you may treat everything in it as a new fresh page in your mental process. I bet the way of approaching to the problem may be very personal or even cultural thing.
– sardok
16 hours ago
add a comment |
Another interesting variation. Thank you.
– Andrew Truckle
yesterday
Personally, I'd usually avoid nesting if statements if possible. While this case is nice and readable, once new possibilities are added, the nesting can become very hard to read. But if the scenarios never change, it definitly is a nice and readable solution.
– Dnomyar96
16 hours ago
@Dnomyar96 i agree. I personally avoid nested ifs too. Sometimes if the logic is complicated, it is easier for me to understand the logic by breaking it down into the pieces. For example, once you enterbValue1
block, then you may treat everything in it as a new fresh page in your mental process. I bet the way of approaching to the problem may be very personal or even cultural thing.
– sardok
16 hours ago
Another interesting variation. Thank you.
– Andrew Truckle
yesterday
Another interesting variation. Thank you.
– Andrew Truckle
yesterday
Personally, I'd usually avoid nesting if statements if possible. While this case is nice and readable, once new possibilities are added, the nesting can become very hard to read. But if the scenarios never change, it definitly is a nice and readable solution.
– Dnomyar96
16 hours ago
Personally, I'd usually avoid nesting if statements if possible. While this case is nice and readable, once new possibilities are added, the nesting can become very hard to read. But if the scenarios never change, it definitly is a nice and readable solution.
– Dnomyar96
16 hours ago
@Dnomyar96 i agree. I personally avoid nested ifs too. Sometimes if the logic is complicated, it is easier for me to understand the logic by breaking it down into the pieces. For example, once you enter
bValue1
block, then you may treat everything in it as a new fresh page in your mental process. I bet the way of approaching to the problem may be very personal or even cultural thing.– sardok
16 hours ago
@Dnomyar96 i agree. I personally avoid nested ifs too. Sometimes if the logic is complicated, it is easier for me to understand the logic by breaking it down into the pieces. For example, once you enter
bValue1
block, then you may treat everything in it as a new fresh page in your mental process. I bet the way of approaching to the problem may be very personal or even cultural thing.– sardok
16 hours ago
add a comment |
up vote
0
down vote
My 2 cents: declare a variable sum (integer) so that
if(bValue1)
{
sum=sum+1;
}
if(bValue2)
{
sum=sum+2;
}
if(bValue3)
{
sum=sum+4;
}
if(bValue4)
{
sum=sum+8;
}
Check sum against the conditions you want and that's it.
This way you can add easily more conditions in the future keeping it quite straightforward to read.
add a comment |
up vote
0
down vote
My 2 cents: declare a variable sum (integer) so that
if(bValue1)
{
sum=sum+1;
}
if(bValue2)
{
sum=sum+2;
}
if(bValue3)
{
sum=sum+4;
}
if(bValue4)
{
sum=sum+8;
}
Check sum against the conditions you want and that's it.
This way you can add easily more conditions in the future keeping it quite straightforward to read.
add a comment |
up vote
0
down vote
up vote
0
down vote
My 2 cents: declare a variable sum (integer) so that
if(bValue1)
{
sum=sum+1;
}
if(bValue2)
{
sum=sum+2;
}
if(bValue3)
{
sum=sum+4;
}
if(bValue4)
{
sum=sum+8;
}
Check sum against the conditions you want and that's it.
This way you can add easily more conditions in the future keeping it quite straightforward to read.
My 2 cents: declare a variable sum (integer) so that
if(bValue1)
{
sum=sum+1;
}
if(bValue2)
{
sum=sum+2;
}
if(bValue3)
{
sum=sum+4;
}
if(bValue4)
{
sum=sum+8;
}
Check sum against the conditions you want and that's it.
This way you can add easily more conditions in the future keeping it quite straightforward to read.
answered 11 hours ago
SCdev
168
168
add a comment |
add a comment |
up vote
0
down vote
You won't have to worry about invalid combinations of boolean flags if you get rid of the boolean flags.
The acceptable values are:
Scenario 1 | Scenario 2 | Scenario 3
bValue1: true | true | true
bValue2: true | true | false
bValue3: true | true | false
bValue4: true | false | false
You clearly have three states. It'd be better to model that and to derive the boolean properties from those states, not the other way around.
enum State
{
scenario1,
scenario2,
scenario3,
};
bool isValue1(State s)
{
// (Well, this is kind of silly. Do you really need this flag?)
return true;
}
bool isValue2(State s)
{
switch (s)
{
case scenario1:
case scenario2:
return true;
case scenario3:
return false;
}
}
bool isValue3(State s)
{
// (This is silly too. Do you really need this flag?)
return isValue2(s);
}
bool isValue4(State s)
{
switch (s)
{
case scenario1:
return true;
case scenario2:
case scenario3:
return false;
}
}
If your boolean values can change dynamically, then instead of toggling individual boolean flags (which could result in invalid combinations of flags), you instead can have a state machine that transitions from one scenario to another.
add a comment |
up vote
0
down vote
You won't have to worry about invalid combinations of boolean flags if you get rid of the boolean flags.
The acceptable values are:
Scenario 1 | Scenario 2 | Scenario 3
bValue1: true | true | true
bValue2: true | true | false
bValue3: true | true | false
bValue4: true | false | false
You clearly have three states. It'd be better to model that and to derive the boolean properties from those states, not the other way around.
enum State
{
scenario1,
scenario2,
scenario3,
};
bool isValue1(State s)
{
// (Well, this is kind of silly. Do you really need this flag?)
return true;
}
bool isValue2(State s)
{
switch (s)
{
case scenario1:
case scenario2:
return true;
case scenario3:
return false;
}
}
bool isValue3(State s)
{
// (This is silly too. Do you really need this flag?)
return isValue2(s);
}
bool isValue4(State s)
{
switch (s)
{
case scenario1:
return true;
case scenario2:
case scenario3:
return false;
}
}
If your boolean values can change dynamically, then instead of toggling individual boolean flags (which could result in invalid combinations of flags), you instead can have a state machine that transitions from one scenario to another.
add a comment |
up vote
0
down vote
up vote
0
down vote
You won't have to worry about invalid combinations of boolean flags if you get rid of the boolean flags.
The acceptable values are:
Scenario 1 | Scenario 2 | Scenario 3
bValue1: true | true | true
bValue2: true | true | false
bValue3: true | true | false
bValue4: true | false | false
You clearly have three states. It'd be better to model that and to derive the boolean properties from those states, not the other way around.
enum State
{
scenario1,
scenario2,
scenario3,
};
bool isValue1(State s)
{
// (Well, this is kind of silly. Do you really need this flag?)
return true;
}
bool isValue2(State s)
{
switch (s)
{
case scenario1:
case scenario2:
return true;
case scenario3:
return false;
}
}
bool isValue3(State s)
{
// (This is silly too. Do you really need this flag?)
return isValue2(s);
}
bool isValue4(State s)
{
switch (s)
{
case scenario1:
return true;
case scenario2:
case scenario3:
return false;
}
}
If your boolean values can change dynamically, then instead of toggling individual boolean flags (which could result in invalid combinations of flags), you instead can have a state machine that transitions from one scenario to another.
You won't have to worry about invalid combinations of boolean flags if you get rid of the boolean flags.
The acceptable values are:
Scenario 1 | Scenario 2 | Scenario 3
bValue1: true | true | true
bValue2: true | true | false
bValue3: true | true | false
bValue4: true | false | false
You clearly have three states. It'd be better to model that and to derive the boolean properties from those states, not the other way around.
enum State
{
scenario1,
scenario2,
scenario3,
};
bool isValue1(State s)
{
// (Well, this is kind of silly. Do you really need this flag?)
return true;
}
bool isValue2(State s)
{
switch (s)
{
case scenario1:
case scenario2:
return true;
case scenario3:
return false;
}
}
bool isValue3(State s)
{
// (This is silly too. Do you really need this flag?)
return isValue2(s);
}
bool isValue4(State s)
{
switch (s)
{
case scenario1:
return true;
case scenario2:
case scenario3:
return false;
}
}
If your boolean values can change dynamically, then instead of toggling individual boolean flags (which could result in invalid combinations of flags), you instead can have a state machine that transitions from one scenario to another.
edited 9 hours ago
answered 9 hours ago
jamesdlin
25.9k65792
25.9k65792
add a comment |
add a comment |
up vote
0
down vote
Just a personal preference over the accepted answer, but I would write:
bool valid = false;
// scenario 1
valid = valid || (bValue1 && bValue2 && bValue3 && bValue4);
// scenario 2
valid = valid || (bValue1 && bValue2 && bValue3 && !bValue4);
// scenario 3
valid = valid || (bValue1 && !bValue2 && !bValue3 && !bValue4);
add a comment |
up vote
0
down vote
Just a personal preference over the accepted answer, but I would write:
bool valid = false;
// scenario 1
valid = valid || (bValue1 && bValue2 && bValue3 && bValue4);
// scenario 2
valid = valid || (bValue1 && bValue2 && bValue3 && !bValue4);
// scenario 3
valid = valid || (bValue1 && !bValue2 && !bValue3 && !bValue4);
add a comment |
up vote
0
down vote
up vote
0
down vote
Just a personal preference over the accepted answer, but I would write:
bool valid = false;
// scenario 1
valid = valid || (bValue1 && bValue2 && bValue3 && bValue4);
// scenario 2
valid = valid || (bValue1 && bValue2 && bValue3 && !bValue4);
// scenario 3
valid = valid || (bValue1 && !bValue2 && !bValue3 && !bValue4);
Just a personal preference over the accepted answer, but I would write:
bool valid = false;
// scenario 1
valid = valid || (bValue1 && bValue2 && bValue3 && bValue4);
// scenario 2
valid = valid || (bValue1 && bValue2 && bValue3 && !bValue4);
// scenario 3
valid = valid || (bValue1 && !bValue2 && !bValue3 && !bValue4);
answered 56 mins ago
François Gueguen
13
13
add a comment |
add a comment |
up vote
-2
down vote
A simple approach is finding the answer that you think are acceptable.
Yes = (boolean1 && boolean2 && boolean3 && boolean4) + + ...
Now if possible simplify the equation using boolean algebra.
like in this case, acceptable1 and 2 combine to (boolean1 && boolean2 && boolean3)
.
Hence the final answer is:
(boolean1 && boolean2 && boolean3) ||
((boolean1 && !boolean2 && !boolean3 && !boolean4)
add a comment |
up vote
-2
down vote
A simple approach is finding the answer that you think are acceptable.
Yes = (boolean1 && boolean2 && boolean3 && boolean4) + + ...
Now if possible simplify the equation using boolean algebra.
like in this case, acceptable1 and 2 combine to (boolean1 && boolean2 && boolean3)
.
Hence the final answer is:
(boolean1 && boolean2 && boolean3) ||
((boolean1 && !boolean2 && !boolean3 && !boolean4)
add a comment |
up vote
-2
down vote
up vote
-2
down vote
A simple approach is finding the answer that you think are acceptable.
Yes = (boolean1 && boolean2 && boolean3 && boolean4) + + ...
Now if possible simplify the equation using boolean algebra.
like in this case, acceptable1 and 2 combine to (boolean1 && boolean2 && boolean3)
.
Hence the final answer is:
(boolean1 && boolean2 && boolean3) ||
((boolean1 && !boolean2 && !boolean3 && !boolean4)
A simple approach is finding the answer that you think are acceptable.
Yes = (boolean1 && boolean2 && boolean3 && boolean4) + + ...
Now if possible simplify the equation using boolean algebra.
like in this case, acceptable1 and 2 combine to (boolean1 && boolean2 && boolean3)
.
Hence the final answer is:
(boolean1 && boolean2 && boolean3) ||
((boolean1 && !boolean2 && !boolean3 && !boolean4)
edited yesterday
Andrew Truckle
5,16032145
5,16032145
answered 2 days ago
Rupesh
255
255
add a comment |
add a comment |
up vote
-3
down vote
use bit field:
unoin {
struct {
bool b1: 1;
bool b2: 1;
bool b3: 1;
bool b4: 1;
} b;
int i;
} u;
// set:
u.b.b1=true;
...
// test
if (u.i == 0x0f) {...}
if (u.i == 0x0e) {...}
if (u.i == 0x08) {...}
PS:
That's a big pity to CPPers'. But, UB is not my worry, check it at http://coliru.stacked-crooked.com/a/2b556abfc28574a1.
2
This causes UB due to accessing an inactive union field.
– HolyBlackCat
2 days ago
Formally it's UB in C++, you can't set one member of union and read from another. Technically it might be better to implement templated getterssetters for bits of integral value.
– Swift - Friday Pie
2 days ago
I think the behavior would shift to Implementation-Defined if one were to convert the union's address to anunsigned char*
, though I think simply using something like((((flag4 <<1) | flag3) << 1) | flag2) << 1) | flag1
would probably be more efficient.
– supercat
2 days ago
add a comment |
up vote
-3
down vote
use bit field:
unoin {
struct {
bool b1: 1;
bool b2: 1;
bool b3: 1;
bool b4: 1;
} b;
int i;
} u;
// set:
u.b.b1=true;
...
// test
if (u.i == 0x0f) {...}
if (u.i == 0x0e) {...}
if (u.i == 0x08) {...}
PS:
That's a big pity to CPPers'. But, UB is not my worry, check it at http://coliru.stacked-crooked.com/a/2b556abfc28574a1.
2
This causes UB due to accessing an inactive union field.
– HolyBlackCat
2 days ago
Formally it's UB in C++, you can't set one member of union and read from another. Technically it might be better to implement templated getterssetters for bits of integral value.
– Swift - Friday Pie
2 days ago
I think the behavior would shift to Implementation-Defined if one were to convert the union's address to anunsigned char*
, though I think simply using something like((((flag4 <<1) | flag3) << 1) | flag2) << 1) | flag1
would probably be more efficient.
– supercat
2 days ago
add a comment |
up vote
-3
down vote
up vote
-3
down vote
use bit field:
unoin {
struct {
bool b1: 1;
bool b2: 1;
bool b3: 1;
bool b4: 1;
} b;
int i;
} u;
// set:
u.b.b1=true;
...
// test
if (u.i == 0x0f) {...}
if (u.i == 0x0e) {...}
if (u.i == 0x08) {...}
PS:
That's a big pity to CPPers'. But, UB is not my worry, check it at http://coliru.stacked-crooked.com/a/2b556abfc28574a1.
use bit field:
unoin {
struct {
bool b1: 1;
bool b2: 1;
bool b3: 1;
bool b4: 1;
} b;
int i;
} u;
// set:
u.b.b1=true;
...
// test
if (u.i == 0x0f) {...}
if (u.i == 0x0e) {...}
if (u.i == 0x08) {...}
PS:
That's a big pity to CPPers'. But, UB is not my worry, check it at http://coliru.stacked-crooked.com/a/2b556abfc28574a1.
edited yesterday
answered 2 days ago
hedzr
9524
9524
2
This causes UB due to accessing an inactive union field.
– HolyBlackCat
2 days ago
Formally it's UB in C++, you can't set one member of union and read from another. Technically it might be better to implement templated getterssetters for bits of integral value.
– Swift - Friday Pie
2 days ago
I think the behavior would shift to Implementation-Defined if one were to convert the union's address to anunsigned char*
, though I think simply using something like((((flag4 <<1) | flag3) << 1) | flag2) << 1) | flag1
would probably be more efficient.
– supercat
2 days ago
add a comment |
2
This causes UB due to accessing an inactive union field.
– HolyBlackCat
2 days ago
Formally it's UB in C++, you can't set one member of union and read from another. Technically it might be better to implement templated getterssetters for bits of integral value.
– Swift - Friday Pie
2 days ago
I think the behavior would shift to Implementation-Defined if one were to convert the union's address to anunsigned char*
, though I think simply using something like((((flag4 <<1) | flag3) << 1) | flag2) << 1) | flag1
would probably be more efficient.
– supercat
2 days ago
2
2
This causes UB due to accessing an inactive union field.
– HolyBlackCat
2 days ago
This causes UB due to accessing an inactive union field.
– HolyBlackCat
2 days ago
Formally it's UB in C++, you can't set one member of union and read from another. Technically it might be better to implement templated getterssetters for bits of integral value.
– Swift - Friday Pie
2 days ago
Formally it's UB in C++, you can't set one member of union and read from another. Technically it might be better to implement templated getterssetters for bits of integral value.
– Swift - Friday Pie
2 days ago
I think the behavior would shift to Implementation-Defined if one were to convert the union's address to an
unsigned char*
, though I think simply using something like ((((flag4 <<1) | flag3) << 1) | flag2) << 1) | flag1
would probably be more efficient.– supercat
2 days ago
I think the behavior would shift to Implementation-Defined if one were to convert the union's address to an
unsigned char*
, though I think simply using something like ((((flag4 <<1) | flag3) << 1) | flag2) << 1) | flag1
would probably be more efficient.– supercat
2 days ago
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53591559%2fhow-to-improve-logic-to-check-whether-4-boolean-values-match-some-cases%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
7
I would use a table instead of complex
if
statement. Additionally, as these are boolean flags, you can model each scenario as a constant and check against it.– Zdeslav Vojkovic
Dec 3 at 10:16
3
if (!((bValue1 && bValue2 && bValue3) || (bValue1 && !bValue2 && !bValue3 && !bValue4)))
– mch
Dec 3 at 10:17
13
what are the scenarios actually? Often things get much simpler if you just give stuff proper names, eg
bool scenario1 = bValue1 && bValue2 && bValue3 && bValue4;
– user463035818
Dec 3 at 10:57
4
Using meaningful names, you can extract each complex condition into a method and call that method in if condition. It would be much more readable and maintainable. e.g. Take a look at the example provided in the link.refactoring.guru/decompose-conditional
– Hardik Modha
Dec 3 at 12:29
3
FYI en.wikipedia.org/wiki/Karnaugh_map
– 00__00__00
yesterday