使用SFINAE检测成员函数

Using SFINAE to detect a member function

本文关键字:函数 成员 检测 SFINAE 使用      更新时间:2023-10-16

在C++11中,要确定类是否具有成员函数size,可以定义以下测试助手:

template <typename T>
struct has_size_fn
{
    typedef char (& yes)[1];
    typedef char (& no)[2];
    template <typename C> static yes check(decltype(&C::size));
    template <typename> static no check(...);
    static bool const value = sizeof(check<T>(0)) == sizeof(yes);
};

在C++98中,在不依赖typeof之类的编译器扩展的情况下,有类似的技巧吗?

实际上,您的检测可能是错误的。

问题是,您检测到的只是C有一个成员size:

  • 它可能是一个属性
  • 它可以是一个具有任何签名的方法
  • 甚至可能有几种方法(具有各种签名)

如果您希望加强检测,则应尝试仅检测右侧size(无论右侧是什么)。这里是这样一个硬化的检测。

template <typename T>
class has_size {
private:
  typedef char Yes;
  typedef Yes No[2];
  template <typename U, U> struct really_has;
  template <typename C> static Yes& Test(really_has <size_t (C::*)() const,
                                        &C::size>*);
  // EDIT: and you can detect one of several overloads... by overloading :)
  template <typename C> static Yes& Test(really_has <size_t (C::*)(),
                                        &C::size>*);
  template <typename> static No& Test(...);
public:
    static bool const value = sizeof(Test<T>(0)) == sizeof(Yes);
};

编辑:带有过载。

处理不正确的size成员的诀窍是really_has结构。我并不假装它是完美的,尽管。。。

在C++11中,事情更简单(尽管同样冗长),因为您可以通过直接使用来检测事情。因此,等效特性是:

template <typename T>
class has_size {
private:
  typedef char Yes;
  typedef Yes No[2];
  template<typename C> static auto Test(void*)
    -> decltype(size_t{std::declval<C const>().size()}, Yes{});
  template<typename> static No& Test(...);
public:
    static bool const value = sizeof(Test<T>(0)) == sizeof(Yes);
};

然而,C++中推荐的方法是如果可以的话,不要使用traits;例如,在函数中,您可以在类型签名中使用decltype权限。