I need a way to validate that a constant string doesn't contain a certain character at compile time. I thought about using static_assert, but hit a brick wall because I was trying using the .find method, which is not constant.
I have an option of doing the check in the constructor of the class (instances are static const
members of the said class).
But before biting the bullet (since changing the constructor behavior has other implications), I'd like to see if anyone else has one of those creative out-of-the-box ideas to still get this done, preferably at compile time.
By constant string perhaps you mean a string literal, for std::string
can not be used in a constant expression.
In the string literal case we can take advantage of constexpr
: (Live Demo)
template<int N>
constexpr bool has_forbidden_char(const char (&str) [N], char forbidden)
{
for(int i = 0; i < N; ++i)
{
if (str[i] == forbidden)
return true;
}
return false;
}
int main()
{
static_assert(!has_forbidden_char("foobar", 'x'));
static_assert(has_forbidden_char("foobar", 'f'));
}
Edit: iterate to N-1
if you assume you will only receive string literals and not arbitrary character arrays. In this way you won't be checking the NULL character '\0' each time. (zero-length arrays do not exist in C++, so no worry about indexing at -1)
//...
for(int i = 0; i < N-1; ++i){ //...
Edit2: Since you're using Visual Studio 2015, which doesn't have relaxed constexpr
functionality, here's a C++11 conforming solution that works:
namespace detail {
template<int N>
constexpr bool has_forbidden_char_help(const char(&str)[N], char forbidden, int index)
{
return (index < N && (str[index] == forbidden || has_forbidden_char_help(str, forbidden, index+1)));
}
} // namespace detail
template<int N>
constexpr bool has_forbidden_char(const char (&str) [N], char forbidden)
{
return detail::has_forbidden_char_help(str, forbidden, 0);
}
int main()
{
static_assert(!has_forbidden_char("foobar", 'x'), "foobar doesn't have x, so this shouldn't fail...");
static_assert(has_forbidden_char("foobar", 'f'), "foobar does have f, so this shouldn't fail...");
}