如何检测具有特定签名的静态成员函数的存在?

Wal*_*ter 3 c++ templates sfinae template-meta-programming c++11

我在SO上发现了几个问题和答案,涉及在编译时(通过SFINAE)检测给定类是否具有某个名称,类型或签名的成员.但是,我找不到一个也适用于静态公共成员函数(当指针到成员的技巧不起作用时).有任何想法吗?

Jar*_*d42 6

以下可能有所帮助:(https://ideone.com/nDlFUE)

#include <cstdint>

#define DEFINE_HAS_SIGNATURE(traitsName, funcName, signature)               \
    template <typename U>                                                   \
    class traitsName                                                        \
    {                                                                       \
    private:                                                                \
        template<typename T, T> struct helper;                              \
        template<typename T>                                                \
        static std::uint8_t check(helper<signature, &funcName>*);           \
        template<typename T> static std::uint16_t check(...);               \
    public:                                                                 \
        static                                                              \
        constexpr bool value = sizeof(check<U>(0)) == sizeof(std::uint8_t); \
    }
Run Code Online (Sandbox Code Playgroud)

然后定义一个特征:

DEFINE_HAS_SIGNATURE(has_foo, T::foo, void (*)(void));
Run Code Online (Sandbox Code Playgroud)


jro*_*rok 5

这是一种方式:

#include <type_traits>

template<typename, typename>
struct has_fun;

template<typename T, typename Ret, typename... Args>
struct has_fun<T, Ret(Args...)> {
    template<typename U, U> struct Check;

    template<typename U>
    static std::true_type Test(Check<Ret(*)(Args...), &U::fun>*);

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

    static const bool value = decltype(Test<T>(0))::value;
};
Run Code Online (Sandbox Code Playgroud)

它是为一个名为的函数编写的fun.像它一样使用它has_fun<T, int(int, int)>::value.

这是另一个:

#include <type_traits>

template<typename, typename>
struct has_fun;

template<typename T, typename Ret, typename... Args>
struct has_fun<T, Ret(Args...)> {

    struct No {}; // need a unique type for the second overload
                  // so it doesn't match Ret and give a false positive
    template<typename U>
    static auto Test(int) -> decltype( U::fun(std::declval<Args>()...) );

    template<typename U>
    static No Test(...);

    static const bool value =
        std::is_same<decltype(Test<U>(0)), Ret>{};
};
Run Code Online (Sandbox Code Playgroud)

测试函数的返回类型是否可转换Ret而不是检查exatch匹配可能是明智的.使用is_convertible而不是is_same在那种情况下,同时检查返回类型是否不同No(正如Yakk所指出的,那里有可以从几乎任何东西构建的类型).


Yak*_*ont 5

只需调用成员函数并在SFINAE上下文中丢弃结果.如果成功,则该方法存在.如果失败,则该方法不会.

// not needed in C++1y
template<class T,class V=void>using enable_if_t=typename enable_if<T,V>::type;

// If the other tests fail, the type T does not have a method `foo` of
// signature Sig.  The class=void parameter is an implementation detail
// that in an industrial quality implementation we would hide in a helper
// template type.
template<class T,class Sig,class=void>struct has_foo:std::false_type{};

// For R(Args...), we attempt to invoke `T::foo` with (Args...), then check
// if we can assign the return value to a variable of type R.
template<class T,class R,class...Args>
struct has_foo<T,R(Args...),
  enable_if_t< // std:: in C++1y
    std::is_convertible<
      decltype( T::foo( std::declval<Args>()... ) ),
      R
    >::value
    && !std::is_same<R, void>::value
  >
>: std::true_type {};
// for `void` return value, we only care if the function can be invoked,
// no convertible test required:
template<class T,class...Args>
struct has_foo<T,void(Args...),
  decltype( void(T::foo( std::declval<Args>()... ) ) )
>: std::true_type {};
Run Code Online (Sandbox Code Playgroud)

使用:

 has_foo< bar, int(int) >::value
Run Code Online (Sandbox Code Playgroud)

检查if是否int r = T::foo( 7 )是有效表达式,而不是确切的签名匹配.

  • 这是你在那里的一段丑陋的代码.+1仍然:) (2认同)