检查成员函数,自由函数和运算符是否存在的统一方法 [英] Unified way for checking the existence of member functions, free functions and operators

查看:83
本文介绍了检查成员函数,自由函数和运算符是否存在的统一方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在这里发现了几个问题,这些问题用于检查给定类型是否存在成员函数,自由函数或运算符。
建议的解决方案可以解决当前的问题,但是每种解决方案都使用不同的方法。
我试图找到一种以相同或至少相似的方式处理这些问题的方法。

I have found several several questions on here that dealt with checking if either a member function, a free function or an operator exists for a given type. The proposed solutions solve the problem at hand but each uses a different approach. I am trying to find a way to deal with each of those problems in an identical or at least similar fashion.

检查类型是否为 C 有一个成员 func 作品:

Checking if a Type C has a member func works:

template<typename, typename T>
    struct has_member {
        static_assert(
            std::integral_constant<T, false>::value,
            "Second template parameter needs to be of function type.");
};

template<typename C, typename Ret, typename... Args>
struct has_member<C, Ret(Args...)> {
private:
    template<typename T, std::enable_if_t<
        std::is_same
        <
            decltype(std::declval<T>().func(std::declval<Args>()...)),
            Ret   
        >::value 
    > * = nullptr >
    static constexpr std::true_type check(T*);

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

    typedef decltype(check<C>(nullptr)) type;

public:
    static constexpr bool value = type::value;
};

此内容取自以下问题的最高答案:
检查某个类是否具有给定签名的成员函数
编译条件刚刚从返回类型移到了模板参数。

This is taken from the most upvoted answer of this question: Check if a class has a member function of a given signature The condition for compilation has just been moved from the return type to a template parameter.

检查 operator + 是否存在也可以:

template<typename C, typename Ret, typename Arg>
struct has_operator {
private:
    template<typename T, std::enable_if_t<
        std::is_same
        <
            decltype(std::declval<T>() + std::declval<Arg>()),
            Ret
        >::value
    > * = nullptr >
    static constexpr std::true_type check(T*);

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

    typedef decltype(check<C>(nullptr)) type;

public:
    static constexpr bool value = type::value;
};

检查是否存在免费功能 free_func 但是不起作用:

Checking, if a free function free_func exists however does not work:

template<typename T>
    struct has_function {
        static_assert(
            std::integral_constant<T, false>::value,
            "Second template parameter needs to be of function type.");
};

template<typename Ret, typename... Args>
struct has_function<Ret(Args...)> {
private:
    template<std::enable_if_t
    <
        std::is_same
        <
            decltype(free_func(std::declval<Args>()...)),
            Ret    
        >::value
    > * = nullptr >
    static constexpr std::true_type check(nullptr_t);

    template<typename = void>
    static constexpr std::false_type check(...);

    typedef decltype(check<>(nullptr)) type;

public:
    static constexpr bool value = type::value;
};

具有以下声明:

struct MyStruct{
    int func(double);
    MyStruct operator+(const MyStruct &);
};

int free_func(double);

我得到以下结果:

std::cout << has_member<MyStruct, int(double)>::value << std::endl; // true
std::cout << has_member<MyStruct, int(double, double)>::value << std::endl; // false

std::cout << has_function<int(double)>::value << std::endl; // true
//std::cout << has_function<int(double, double)>::value << std::endl; // compile error: free_func does not take 2 arguments

std::cout << has_operator<MyStruct, MyStruct, MyStruct>::value << std::endl; // true
std::cout << has_operator<int, int, int>::value << std::endl; // true
std::cout << has_operator<std::vector<int>, std::vector<int>, std::vector<int>>::value << std::endl; // false

我的问题是:尝试检查自由功能时我做错了什么给定名称和签名的存在吗?
如果我删除了 check(Ret *)的第一个声明,则其他模板将被实例化并正确评估为 false
我以为我出错了,因此SFINAE在这里不适用。

My question now is: What am I doing wrong while trying to check if a free function with a given name and signature exists? If I remove the first declaration of check(Ret*) the other template is instanciated and correctly evaluated to false. I am assuming I make some mistake so that SFINAE is not applicable here.

我还尝试向 check <添加其他模板参数/ code>,但是不更改结果。

I also tried adding another template parameter to check, however without changing the outcome.

template<typename T, std::enable_if_t
<
    std::is_same
    <
        decltype(free_func(std::declval<Args>()...)),
        Ret
    >::value
> * = nullptr >
static constexpr std::true_type check(T *);

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

typedef decltype(check<Ret>(nullptr)) type;

我想继续使用 decltype(declval(...) )样式,因为它允许编译器找出是否存在任何可调用的对象,而我不必担心函数是通过值,引用还是const引用接受其参数。

I would like to keep using the decltype(declval(...)) style since it allows the compiler to figure out if anything callable exists and I do not have to care about whether the function takes its arguments by value, by reference or by const reference.

感谢您的帮助。


我一直想知道的另一件事:
删除时 has_member has_function 的基本模板(仅包含 static_assert ), has_member 始终为假,而 has_function 不再编译,并抱怨 free_func 不接受0个参数。
我假设使用函数签名语法时,模板参数未正确绑定到 Ret Args ,但我并不完全了解。
因此,这里的任何解释也将不胜感激。

An additional thing I have been wondering about: When I remove the base templates of has_member and has_function (which only contain a static_assert), has_member always evaluates to false and has_function does not compile anymore and complains that free_funcdoes not accept 0 arguments. I assume that the template arguments are not correctly bound to Ret and Args when using the function signature syntax, but I do not completely understand it. So any explanation here would also be appreciated.


推荐答案


我现在的问题是:尝试检查具有给定名称和签名的自由函数时,我在做错什么?

My question now is: What am I doing wrong while trying to check if a free function with a given name and signature exists?

首先-您无需在此处检查签名。您正在检查给定特定参数列表的调用表达式是否产生特定结果:

First - you're not checking for signatures anywhere here. You're checking to see if a call expression given a particular argument list produces a specific result:

struct X {
    int func(int);
};
static_assert(has_member<X, int(char)>::value, "!"); // doesn't fire

也就是说,您对成员函数的检查与您的成员检查有很大的不同检查自由功能,即哪些模板参数在替换的直接上下文中。在成员函数的情况下, T 是一个函数模板参数,我们尝试将其替换为该表达式:

That said, there's a big difference between your check for member function and your check for free function, and that is which template parameters are in the immediate context of the substitution. In the member function case, T is a function template parameter that we try to substitute into this expression:

template<typename T, std::enable_if_t<
//       ~~~~~~~~~~
    std::is_same
    <
        decltype(std::declval<T>().func(std::declval<Args>()...)),
//               ~~~~~~~~~~~~~~~~~
        Ret   
    >::value 
> * = nullptr >
static constexpr std::true_type check(T*);

在自由函数情况下,没有函数模板参数:

In the free function case, there is no function template parameter:

template<std::enable_if_t
<
    std::is_same
    <
        decltype(free_func(std::declval<Args>()...)),
        Ret    
    >::value
> * = nullptr >
static constexpr std::true_type check(nullptr_t);

可以在实例化点立即替换整个表达式。它不依赖依赖于 check()中的任何参数,而仅依赖于 has_function 。由于 free_func 不能用两个 double 调用,因此替换失败-但这不是在立即替换中这些局部参数,所以这是一个硬错误。您需要对其进行更改,以确保您要替换的内容与您要检查的表达式相关。也就是说, Args ...

This whole expression can be immediately substituted into at the point of instantiation. It doesn't depend on any of the parameters in check(), just the ones from has_function. Since free_func cannot be invoked with two doubles, that substitution fails - but it's not in the immediate context of substituting in those local parameters, so it's a hard error. You need to change it to ensure that what you're substituting is relevant to the expression you're checking. That is, Args...:

template<typename Ret, typename... Args>
struct has_function<Ret(Args...)> {
private:
    template<typename... A, std::enable_if_t
//           ~~~~~~~~~~~~~
    <
        std::is_same
        <
            decltype(free_func(std::declval<A>()...)),
//                             ~~~~~~~~~~~~~~~~~
            Ret    
        >::value
    > * = nullptr >
    static constexpr std::true_type check(nullptr_t);

    template<typename...>
//           ~~~~~~~~~~~
    static constexpr std::false_type check(...);

    typedef decltype(check<Args...>(nullptr)) type;
//                   ~~~~~~~~~~~~~~
public:
    static constexpr bool value = type::value;
};

还请注意,为了使其与非类类型一起使用, free_func 必须在 has_function 定义的范围内。

Note also that in order for this to work with non-class types as arguments, free_func has to be in scope at the point of definition of has_function.

这篇关于检查成员函数,自由函数和运算符是否存在的统一方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆