I have some utility code that I've been using for years to safely call the ctype family of functions, it looks like this:
template<int (&F)(int)>
int safe_ctype(unsigned char c) {
return F(c);
}
And is used like this:
int r = safe_ctype<std::isspace>(ch);
The idea being that it handles the need to cast the input int
to an unsigned value for you in order to prevent undefined behavior. The specifics of this function is somewhat irrelivant though. Here's my question:
Now that in C++17 and later, noexcept
is part of the type system, this is a compile error! Because all of the ctype functions are now noexcept
.
EDIT: The above sentence is incorrect. the ctype family of functions are not noexcept
. I was however getting a compiler error in gcc < 11.2. https://godbolt.org/z/cTq94q5xE
The code works as expected (despite being technically not allowed due to these functions not being addressable) with the latest versions of all 3 major compilers.
I can of course change my function to look like this:
template<int (&F)(int) noexcept>
int safe_ctype(unsigned char c) noexcept {
return F(c);
}
But now it doesn't work when compiled as C++11 or C++14. So I end up having to do something like this:
#if __cplusplus >= 201703L
template<int (&F)(int) noexcept>
int safe_ctype(unsigned char c) noexcept {
return F(c);
}
#else
template<int (&F)(int)>
int safe_ctype(unsigned char c) {
return F(c);
}
#endif
Which is getting increasingly complex for such a simple task. So is there a way to make the function pointer:
- valid for C++11 - C++20
- Accept both noexcept and non-noexcept when in C++17+
?
I tried doing something like this:
template<class F>
int safe_ctype(unsigned char c) noexcept {
return F(c);
}
In the hopes that it would accept "anything", but sadly, no go.
Thoughts?