SFINAE从另一个命名空间测试一个自由函数
我试图想出一个黑客来测试 std :: isnan
是否在预处理器中没有特殊的套管编译器定义,并提出了以下,我期待工作得很好。
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;
}
结果它不检测它。我知道某些 std :: isnan
是在ideone上定义的,因为我手动测试。
Turns out it doesn't detect it. I know for certain std::isnan
is defined on ideone, because I tested that manually.
取消注释上面的标记行,它可以正常工作。
我缺少什么这里?什么解释了这个行为?
What am I missing here? What explains this behaviour?
事情是,using指令不会添加成员到当前的命名空间, std ::
成员仍然可以通过此命名空间中的声明隐藏。
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.
使用std :: isnan
会表现为导入的命名空间的成员被添加到包含 use
-location和导入的命名空间的命名空间中。使用声明是命名空间中的一个正常声明,因此可以使用后面的声明参与重载解析。
using std::isnan
would instead behaves as if the members of the imported namespace were added to the namespace enclosing both the use
-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.
但是,正如评论中指出的,如果函数不存在则产生错误。要解决此问题,您需要将其从您的 detail ::
命名空间。这应该工作,因为导入的定义将在与 dummy
重载相同的级别。您可以将重载到全局命名空间,也可以创建辅助命名空间(在全局命名空间中)和导入。
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 the dummy
overload. You can take the overload to the global namespace, or you can make an auxiliary namespace (in the global namespace) and import both.