Suppose you have a function that takes a boolean argument:
void do_something(bool use_some_option);
This has issues because on the call site, you see something like do_something(false)
which is not very expressive. If you have multiple such options, it gets worse because the parameters could easily be swapped.
Therefore it is often recommended to use strong types instead of bools, for example an enum class
. However, you have to define that enum somewhere and it is also quite cumbersome to use an enum class
in conditional statements.
My problem with enum class option : bool { no, yes };
is that you cannot use something like if(use_option){...}
.
This problem arises quite often in a large codebase, so it would be nice to have a default way to deal with this issue in a convenient way. My current solution looks like this:
template<typename Name>
class Option {
public:
explicit Option(bool enabled): _enabled(enabled) {}
operator bool() { return _enabled; }
private:
bool _enabled;
};
This can now be used like this:
using UseMyOption = Option<struct UseMyOption_>;
void do_something(UseMyOption use_my_option) {
if(use_my_option) {
...
}
}
Are there any problems with this design for this quite general problem? Are there any issues with an an implicit conversion back to a bool that I am overseeing or is there some further functionality that should be supported?
EDIT:
It seems like the code can be replaced by
enum UseMyOption : bool {};
Is there any behavioral difference to the above implementation? I also wonder why I have never seen a recommendation to use that pattern before because to me this seems to be very useful. Is there any problem with this?
struct DoSomethingOpts { bool use_option; };
then you could even use designated initializers to do stuff likedo_something({.use_option = false});
– Geodesicif(use_option == option::yes)
instead ofif(use_option)
. – Grimsleyenum class option : bool { no, yes };
toenum option : bool { no, yes };
. Use namespaces or enclosing struct or class to limit the pollution. – Uriando_something(no)
. – Grimsleyyes
andno
is no more expressive thantrue
andfalse
. It's not a good example. It's more for things like where abool
parameter calledis_case_sensitive
is less expressive that an enum calledcase_sensitivity
with valuescase_sensitive
andcase_insensitive
in that of thoughtif(case_sensitivity)
lacks expression and if(case_sensitivity=case_sensitive)` would be preferred anyway. – Physicochemicalenum is_case_sensitive : bool {};
? (I was not aware that this is valid syntax...) – Grimsleybool
to theenum
. This is the problematic direction for the application of flags. (andbool
converts toint
anyway) – Grimsleybool
s (just with compiler support and expressiveness) for several reasons (refactoring, less code, easier to write...). – Grimsleytrue
/false
are not expressive enough, but you're fine withyes
/no
. It's unclear what makes for a good solution, since your definition doesn't seem particular firm. Perhaps you could just write the pseudo-code you want to be able to write (both at the call site and test site) and say that you want to do something like that. – Atalantebool
, butbool
should not implicitly convert to it. And I also want to know, why this should be a bad idea to do when using boolean option parameters. I am happier withyes/no
because it is less likely to be used thantrue
andfalse
(and when refactoring, the code fails), but I have also stated that this is a drawback (and the reason why I preferenum option : bool {};
). In the question is an example of pseudo-code what I want to achieve. This is not achievable withenum class
. – Grimsleycompare(bool caseSensitive)
, one could havecompare_case_sensitive()
andcompare_case_insensitive()
. If you have several bool parameters, maybe only certain combinations make sense and represent a specific domain concept. Again, separate functions might be better. – Armeniancompare_case_sensitive_ascending()
,compare_case_sensitive_descending()
,compare_case_insensitive_ascending()
,compare_case_insensitive_descending()
and so on... – Physicochemicalbool
. One could use a similar argument that if an enumeration has 3 (255?) values, it is ok to be represented as anunsigned char
. Strongly typed is strongly typed. – Clime