使用SFINAE检测模板化成员函数的存在

Jes*_*Jes 7 c++ templates sfinae c++11

我了解到SFINAE可用于确定成员函数是否存在于类中.例如,以下代码可用于检查方法hello是否存在于类中.

struct has_method_hello {

  using yes = char[1];
  using no  = char[2];

  template <typename U, typename C>
  static constexpr yes& test(decltype(&U::hello));

  template <typename>
  static constexpr no& test(...);

  static constexpr bool value = (sizeof(yes) == sizeof(test<T>(nullptr)));

}; 

struct Foo {
  void hello() {}
}

std::cout << has_method_hello <Foo> :: value << std::endl;  // 1
Run Code Online (Sandbox Code Playgroud)

但是,假设hello是模板化的,我该如何修改技巧以使它仍能正常运行?

struct Foo {
  template <typename T>
  void hello(T&) {...}
}
Run Code Online (Sandbox Code Playgroud)

Yak*_*ont 5

从这里:

namespace details {
  template<template<class...>class Z, class, class...>
  struct can_apply:std::false_type{};
  template<template<class...>class Z, class...Ts>
  struct can_apply<Z, std::void_t<Z<Ts...>>, Ts...>:
    std::true_type{};
}

template<template<class...>class Z, class...Ts>
using can_apply=details::can_apply<Z, void, Ts...>;
Run Code Online (Sandbox Code Playgroud)

现在你想知道是否foo.hello(int&)可以调用:

我们为hello_r您提供了调用的返回类型.hello

template<class F, class...Ts>
using hello_r = decltype(std::declval<F>().hello( std::declval<Ts>()... ));
Run Code Online (Sandbox Code Playgroud)

这导致can_hello

template<class F, class...Ts>
using can_hello = can_apply<hello_r, F, Ts...>;
Run Code Online (Sandbox Code Playgroud)

现在

struct Foo {
  template <typename T>
  void hello(T&) {...}
};
int main() {
  std::cout << can_hello<Foo&, int&>::value << '\n';
  std::cout << can_hello<Foo&, char&>::value << '\n';
  std::cout << can_hello<Foo&>::value << '\n';
}
Run Code Online (Sandbox Code Playgroud)

打印 110。

活生生的例子


Aru*_*nmu 4

首先,向您展示原始代码的缩短版本:

template <typename T>
struct has_method_hello {

  static constexpr auto test(int) -> decltype(std::declval<T&>().hello(), std::true_type());

  static constexpr std::false_type test(...);

  using result_type = decltype(test(0));
  static const bool value = result_type::value;

};

struct Foo {
  void hello() {}
};
Run Code Online (Sandbox Code Playgroud)

现在使其适用于模板参数,很简单,一个示例:

template <typename T>
struct has_method_hello {

  static constexpr auto test(int) -> decltype(std::declval<T&>().hello(std::declval<int&>()), std::true_type());

  static constexpr std::false_type test(...);

  using result_type = decltype(test(0));
  static const bool value = result_type::value;

};

struct Foo {
  template <typename T>
  void hello(T& v) {}
};
Run Code Online (Sandbox Code Playgroud)

请注意,我int在这里有硬编码类型。您也可以制作模板的该部分has_method_hello