其他检查类是否具有某个成员函数的方法

我们来检查一下

struct Thing {
    int foo(double, bool) {return 0;}
};

在编译期间具有int foo(double, bool)成员函数。 有很多方法可以做到这一点,大多数只是其他的变种。 有人能想出一种与我在这里提到的5种方式截然不同(或者至少相当有创意)的方式吗? 我只是想通过模板和SFINAE学习一些新技术。

#include <iostream>
#include <type_traits>

// Using void_t (this includes using std::is_detected).
template <typename T>
using void_t = void;

template <typename T, typename = void>
struct has_foo : std::false_type {};

template <typename T>
struct has_foo<T,
        void_t<decltype(static_cast<int>(std::declval<T>().foo(double{}, bool{})))>
    > : std::true_type {};

// Using the ... default argument.
template <typename T>
struct hasfoo {
    template <typename U>
    static std::true_type test (decltype(static_cast<int(T::*)(double, bool)>(&T::foo))*);  // or 'decltype(static_cast<int>(std::declval<U>().foo(double{}, bool{})))*' works fine too.

    template <typename>
    static std::false_type test (...);

    static constexpr bool value = decltype(test<T>(nullptr))::value;
};

// Overloads and trailing return types.
template <typename>
struct Helper : std::true_type {};

template <typename T>
auto helper(int) -> Helper<decltype(static_cast<int>(std::declval<T>().foo(double{}, bool{})))>;

template <typename>
std::false_type helper(long);

template <typename T>
constexpr bool hasFoo() {return decltype(helper<T>(0))::value;}

// Comma operator (basically the same as the above).
template <typename T>
auto check(int) -> decltype(static_cast<int>(std::declval<T>().foo(double{}, bool{})), std::true_type{});

template <typename T>
std::false_type check(...);

template <typename T>
using HasFoo = decltype(check<T>(0));

// Member function pointer template parameter.
template <typename T>
struct Hasfoo {
    template <typename U, int(U::*)(double, bool)>
    struct Tag;

    template <typename U>
    static constexpr bool test (Tag<U, &U::foo>*) {return true;}

    template <typename>
    static constexpr bool test (...) {return false;}

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

// Tests
struct Thing {
    int foo(double, bool) {return 0;}
};

int main() {
    static_assert (has_foo<Thing>::value, "");
    static_assert (hasfoo<Thing>::value, "");
    static_assert (hasFoo<Thing>(), "");
    static_assert (HasFoo<Thing>::value, "");
}

编辑:我只记得雅克在不久前提出了一个不同的问题的优雅和更一般的解决方案(这里是他的实际类型,修改只是为了匹配foo函数):

namespace meta {
  namespace details {
    template<template<class...>class Z, class=void, class...Ts>
    struct can_apply : std::false_type {};
    template<template<class...>class Z, class...Ts>
    struct can_apply<Z, decltype((void)(std::declval<Z<Ts...>>())), Ts...>:
      std::true_type
    {};
  }
  template<template<class...>class Z, class...Ts>
  using can_apply = details::can_apply<Z,void,Ts...>;
}

template<class T>
using member_foo = decltype(static_cast<int(T::*)(double, bool)>(&T::foo));

template<class T>
using has_member_foo = meta::can_apply<member_foo, T>;

有人能想出一种与我在这里提到的5种方式截然不同(或者至少相当有创意)的方式吗?

一个相当有创意的方式可以做到这一点。
它基于noexcept运算符和一个简单的使用声明(这里命名为Type )。
剩下的就是SFINAE和部分模板专业化。

它遵循一个最小的工作示例:

#include<type_traits>
#include<utility>

template<typename T, bool>
using Type = T;

template<typename T, typename = T>
struct U: std::false_type {};

template<typename T>
struct U<T, Type<T, noexcept(std::declval<T>().f(42))>>: std::true_type {};

struct S { void f(int) {} };
struct T {};

int main() {
    static_assert(U<S>::value, "!");
    static_assert(not U<T>::value, "!");
}

如果与其他解决方案相比,该解决方案存在问题。
作为一个例子,下面的结构体也会通过测试:

struct R { int f(double) {} };

换句话说,只要要测试的函数接受一个可以转换为42的类型的参数,并且不管返回类型是什么,它都被接受。


有人能想出一种与我在这里提到的5种方式截然不同(或者至少相当有创意)的方式吗?

一个相当有创意的方式可以做到这一点。
它基于sizeof运算符和一个简单的使用声明(这里命名为Type )。
剩下的就是SFINAE和部分模板专业化。

它遵循一个最小的工作示例:

#include<type_traits>
#include<cstddef>

template<typename T, std::size_t>
using Type = T;

template<typename T, typename = T>
struct U: std::false_type {};

template<typename T>
struct U<T, Type<T, sizeof(static_cast<void(T::*)(int)>(&T::f))>>: std::true_type {};

struct S { void f(int) {} };
struct R { int f(double) { return 42; } };
struct T {};

int main() {
    static_assert(U<S>::value, "!");
    static_assert(not U<R>::value, "!");
    static_assert(not U<T>::value, "!");
}

有人能想出一种与我在这里提到的5种方式截然不同(或者至少相当有创意)的方式吗?

一个相当有创意的方式可以做到这一点。
它不利用任何未评估的上下文。 相反,它依赖于一个简单的使用声明(这里命名为Type ),这就是全部。
剩下的就是SFINAE和部分模板专业化。

它遵循一个最小的工作示例:

#include<type_traits>

template<typename T, void(T::*)(int)>
using Type = T;

template<typename T, typename = T>
struct U: std::false_type {};

template<typename T>
struct U<T, Type<T, &T::f>>: std::true_type {};

struct S { void f(int) {} };
struct R { int f(double) { return 42; } };
struct T {};

int main() {
    static_assert(U<S>::value, "!");
    static_assert(not U<R>::value, "!");
    static_assert(not U<T>::value, "!");
}
链接地址: http://www.djcxy.com/p/91155.html

上一篇: Other ways of checking if a class has a certain member function

下一篇: Coq simpl for Program Fixpoint