Не могу заставить SFINAE работать в детекторе функций - PullRequest
1 голос
/ 18 января 2012

Я работал над некоторыми решениями для некоторых недавно опубликованных вопросов, в которых первоначальные спрашивающие пытались выяснить, существует ли метод в данном классе. Я пытался разработать решение, используя подход SFINAE, но, к сожалению, я продолжаю появляться пустым.

Вот моя попытка найти решение, которое не работает для класса, которое позволяет нам определить, есть ли у другого класса метод с именем function():

#include <iostream>

using namespace std;

struct sample_class
{
    void function() {}
};


template<typename T>
class test_size_call
{
    private:
        typedef char yes;
        typedef char (&no)[2];
        int tester[1];

        template <unsigned int>
        struct helper { static const unsigned int value = 1; };

        template<typename R>
        static yes test(int (&a)[helper<sizeof(std::declval<R>().function(), 0)>::value]);

        /* template<typename R>
        static no test(...); */

    public:
        static const bool value = (sizeof(test<T>(tester)) == sizeof(yes));
};


int main()
{
    cout << "Has function() method: " << test_size_call<sample_class>::value << endl;
        return 0;
}

Результаты, если вы раскомментируете функцию catch-all test, продолжат отображаться как false. С закомментированной функцией я получаю ошибку компилятора, что нет версии test, которая будет принимать аргумент int (&)[1]. Мне любопытно, почему declval<R>().function() не выглядит должным образом. Например, если я изменил это на что-то очень явное, например declval<T>().function(), то это сработает. К сожалению, это не SFINAE, потому что, если в классе нет метода function(), вместо тихого сбоя, я получаю ошибку компилятора.

Я уверен, что здесь есть что-то очень простое, чего мне не хватает. Спасибо за любую помощь, вы можете предоставить.

Ответы [ 2 ]

3 голосов
/ 18 января 2012

Должно быть проблема с вашим компилятором, Clang правильно печатает 1 и 0 для следующего кода:

#include <utility>

template<typename T>
class test_size_call
{
    private:
        typedef char yes;
        typedef char (&no)[2];
        int tester[1];

        template <unsigned int>
        struct helper { static const unsigned int value = 1; };

        template<typename R>
        static yes test(int (&a)[helper<sizeof(std::declval<R>().function(), 0)>::value]);

        template<typename R>
        static no test(...);

    public:
        static const bool value = (sizeof(test<T>(tester)) == sizeof(yes));
};

#include <iostream>

struct sample_class
{
    void function() {}
};

struct sample_class2{};

int main()
{
    std::cout << "Has function() method: " << test_size_call<sample_class>::value << '\n';
    std::cout << "Has function() method 2: " << test_size_call<sample_class2>::value << '\n';
    return 0;
}

В то время как GCC 4.5.1 не . Обратите внимание, что это исправлено в GCC 4.7, как указано здесь .

2 голосов
/ 18 января 2012

Джейсон, если вы используете Visual C ++, то SFINAE там работает не очень хорошо (в частности, он, кажется, не работает для членов данных пользовательских типов, но все же может работать для функций).

Для других компиляторов вы можете использовать что-то вроде этого:

template <typename T>
struct has_function
{
  template <typename U, void (U::*f) ()> struct match_;
  template<typename > static char (&select_(...))[2];
  template<typename U> static char (&select_(match_<U, &U::function>* ))[1];

  enum { value = sizeof(select_<T>(0)) == 1 };
};

struct get
{
  void function();
};

int main()
{
  int t[(int)has_function<get>::value];
  (void)t;
}

Существует обходной путь для ошибки Visual C ++, проверьте вкладку Временные решения здесь: http://connect.microsoft.com/VisualStudio/feedback/details/718729/c-type-equality-not-recognized-under-sfinae-context

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...