I was trying to come up with a hack to test if std::isnan
is defined without special casing compilers in the preprocessor, and came up with the following, which I was expecting to work fine.
#include <cmath>
#include <type_traits>
namespace detail {
using namespace std;
struct dummy {};
void isnan(dummy);
//bool isnan(float); // Just adding this declaration makes it work!
template <typename T>
struct is_isnan_available {
template <typename T1>
static decltype(isnan(T1())) test(int);
template <typename>
static void test(...);
enum { value = !std::is_void<decltype(test<T>(0))>::value };
};
}
int main() {
return detail::is_isnan_available<float>::value;
}
Turns out it doesn't detect it. I know for certain std::isnan
is defined on ideone, because I tested that manually.
And when I uncomment the marked line above, it works.
What am I missing here? What explains this behaviour?
The thing is, that the using directive doesn't add members to the current namespace, so the
std::
members could still be hidden by declarations in this namespace.using std::isnan
would instead behaves as if the members of the imported namespace were added to the namespace enclosing both theuse
-location and the imported namespace. The using declaration is a normal declaration in the namespace, so can take part in overload resolution with the declarations that follow.However, as pointed out in the comments, that would produce an error if the function does not exist. To work around that you need to put it out of your
detail::
namespace then. That should work, because the imported definition would be at the same level as thedummy
overload. You can take the overload to the global namespace, or you can make an auxiliary namespace (in the global namespace) and import both.I solved this problem for the set of POSIX thread-safe APIs which supersede non-thread-safe standard functions: C++11 alternative to localtime_r . This code detects whether an API is defined in the global namespace, and if it does not exist, selects a custom workaround.