I am trying to use an if statement to check if a user inputted day of the week (3-digit string i.e "Fri") is equal to a weekday. The user inputted variable is stored in "dayOfWeek"
I wanted to do this with the following code:
if (dayOfWeek == ("Mon"|| "Tue" || "Wed" || "Thu" || "Fri")){
}
I was hoping this code would read as "if day of the week is equal to "Mon" or "Tue ... etc" so that the if statement would return true for any of these inputs
I then received the following error message:
Invalid operands to binary expression ('std::string' (aka 'basic_string') and 'bool')
I understand that one possible fix is to repeat "dayOfWeek ==" for each input, but this does not seem intuitive and would create a very long if statement.
Is my approach not possible or is there a better approach?
CodePudding user response:
sadly c isnt English, as you found out. You need
if (dayOfWeek == "Mon"||
dayOfWeek == "Tue" ||
dayOfWeek == "Wed" ||
dayOfWeek == "Thu" ||
dayOfWeek == "Fri"){
}
You ask for the most efficient - I missed that.
This is it for sure.
Is it the most 'elegant' and 'flexible'? - no
The answer with the set is certainly elegant and flexible, but for me it obscures the intent, especially if the set def is distant from the check code
CodePudding user response:
Here there is an example
#include<iostream>
#include<vector>
#include <set>
#include <string>
int main()
{
std::set<std::string> container = {
"Mon",
"Tue" ,
"Wed" ,
"Thu" ,
"Fri"
};
std::cout<<(container.find("Mon") != container.end());
}
If you want more stuff about sets check the this guide
Hope it will be helpful
CodePudding user response:
With a little bit of other work, we can make almost the desired syntax work, and work reasonably efficiently as well.
We start by defining a string_set
type to hold the set of strings we're going to search in:
class string_set {
std::vector<std::string_view> strings;
public:
string_set(std::string_view s) { strings.push_back(s); }
string_set& operator (std::string_view s) { strings.push_back(s); return *this; }
string_set& operator (string_set const &other) {
std::copy(other.strings.begin(), other.strings.end(), std::back_inserter(strings));
return *this;
}
string_set& operator||(string_set const &other) { return *this other; }
string_set& operator||(std::string_view other) { return *this other;}
friend bool operator==(std::string_view s, string_set const &ss ) {
return std::any_of(ss.strings.begin(), ss.strings.end(),
[&](std::string_view t) { return s == t; }
);
}
};
Then we define a user-defined literal operator to create one of those from a string:
// uses implicit conversion from `string_view` to `string_set`.
// Some may prefer to do that explicitly.
string_set operator"" _ss(char const *s, std::size_t len) { return std::string_view(s, len); }
With these in place, we can create a string_set and test for membership like this: if (input == "Mon"_ss "Tue" "Wed" "Thu" "Fri")
. If you prefer to use ||
instead of
, you can do that, but since its precedence is lower, you need to enclose the strings in parentheses: if (input == ("Mon"_ss || "Tue" || "Wed" || "Thu" || "Fri"))
.
The ==
operator does a linear search in the strings we've given. This wouldn't be a good idea if there were a lot of strings, but this is intended to be used as above, with a set of strings specified directly in the if
statement, so we're optimizing for small sets--think of something like a dozen or so as an upper bound.
Of course, if we really wanted something that worked more efficiently for a lot of strings, we could do that too. For example, instead of a vector of string_view
and a linear search, we could build a trie, and search that. This would tend to optimize search speed at the expense of more time building the trie to start with, so if we did that we'd probably want to (for one possibility) make the building phase constexpr
, so it could/would all happen at compile time. At least in my opinion, for a first cut at things, this would be pretty serious overkill though.
Since it uses std::string_view
, this does require C 17 or higher.