SFINAE 用于测试另一个命名空间中的自由函数

发布于 2024-12-25 00:09:37 字数 927 浏览 1 评论 0原文

我试图想出一个 hack 来测试 std::isnan 是否在预处理器中没有特殊大小写编译器的情况下定义,并提出了以下内容,我希望它能正常工作。

#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 上定义的,因为我手动测试了它。

当我取消上面标记行的注释时,它就起作用了。

我在这里缺少什么?如何解释这种行为?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

黯淡〆 2025-01-01 00:09:37

问题是,using 指令不会将成员添加到当前命名空间,因此 std:: 成员仍然可以被该命名空间中的声明隐藏。

using std::isnan 的行为就像将导入的命名空间的成员添加到包含 use 位置和导入的命名空间的命名空间中一样。 using 声明是命名空间中的普通声明,因此可以使用后面的声明参与重载决策。

但是,正如评论中指出的,如果该函数不存在,则会产生错误。要解决此问题,您需要将其从您的 detail:: 命名空间中删除。这应该可行,因为导入的定义将与虚拟重载处于同一级别。您可以将重载带到全局命名空间,也可以创建一个辅助命名空间(在全局命名空间中)并导入两者< /a>.

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 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.

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.

江湖正好 2025-01-01 00:09:37

我为一组取代非线程安全标准函数的 POSIX 线程安全 API 解决了这个问题: localtime_r 的 C++11 替代方案。此代码检测全局命名空间中是否定义了 API,如果不存在,则选择自定义解决方法。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文