SFINAE для тестирования свободной функции из другого пространства имен - PullRequest
8 голосов
/ 06 января 2012

Я пытался придумать хак, чтобы проверить, определен ли 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, потому что я проверял это вручную.

И когда я раскомментирую отмеченную строку над , это работает.

Что такоеЯ здесь скучаю?Чем объясняется такое поведение?

Ответы [ 2 ]

7 голосов
/ 06 января 2012

Дело в том, что директива using не добавляет членов в текущее пространство имен, поэтому члены std:: все еще могут быть скрыты объявлениями в этом пространстве имен.

Вместо этого

using std::isnan будет вести себя так, как если бы члены импортированного пространства имен были добавлены в пространство имен, включающее как use -положение, так и импортированное пространство имен. Объявление using является обычным объявлением в пространстве имен, поэтому может участвовать в разрешении перегрузки с помощью следующих объявлений.

Однако, как указано в комментариях, это приведет к ошибке, если функция не существует. Чтобы обойти это, вам нужно убрать его из вашего detail:: пространства имен, затем . Это должно работать, потому что импортированное определение будет на том же уровне, что и перегрузка dummy. Вы можете перегрузить глобальное пространство имен или создать вспомогательное пространство имен (в глобальном пространстве имен) и импортировать оба .

1 голос
/ 06 января 2012

Я решил эту проблему для набора многопоточных API POSIX, которые заменяют не поточно-безопасные стандартные функции: C ++ 11 альтернатива localtime_r .Этот код определяет, определен ли API в глобальном пространстве имен, и, если он не существует, выбирает пользовательский обходной путь.

...