无法让SFINAE在功能检测器中工作

Can't get SFINAE to work in function detector

本文关键字:检测器 工作 功能 SFINAE      更新时间:2023-10-16

我一直在为最近发布的一些问题制定一些解决方案,其中原始提问者一直试图查询给定类中是否存在方法。我一直在尝试使用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()方法,而不是静默地失败,我会得到一个编译器错误。

我确信我在这里错过了一些非常简单的东西。感谢您提供的任何帮助。

编译器一定有问题,Clang正确打印了以下代码的10

#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中得到了修复。

Jason,如果您使用的是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