c++ std::是否成员函数指针不适用于重载函数?[duplicate]

r7s23pms  于 2023-02-20  发布在  其他
关注(0)|答案(1)|浏览(135)
    • 此问题在此处已有答案**:

Checking for existence of an (overloaded) member function(3个答案)
昨天关门了。
我写了一个trait,通过std::is_member_function_pointer检测类是否有某个公共成员函数:

class Test1
{
public:
    void method();
};

class Test2
{
public:
    void method();
    void method(int);
};

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

template <typename T>
struct HasMethod<T, std::enable_if_t<std::is_member_function_pointer<decltype(&T::method)>::value>>
    : std::true_type
{
};

int main()
{
    std::cout << HasMethod<Test1>::value << std::endl; // prints 1
    std::cout << HasMethod<Test2>::value << std::endl; // prints 0
}

然而,当函数被重载时,std::is_member_function_pointer似乎无法检测到它,如Test2所示。是否有一种方法可以使它工作,而不管方法是否被重载?

v8wbuo2f

v8wbuo2f1#

要检测类成员的存在,通常的方法是使用std::void_t模板。您可以这样做:

#include <iostream>
#include <type_traits>

class Test1
{
public:
    void method();
};

class Test2
{
public:
    void method();
    void method(int);
};

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

// Use method(0) to detect void method(int) overload
// You don't even need std::void_t in this case, since method returns void anyway, but for any other return type you will need it
template <typename T>
struct HasMethod<T, std::void_t<decltype(std::declval<T>().method())>>
    : std::true_type
{
};

int main()
{
    std::cout << HasMethod<Test1>::value << std::endl; // prints 1
    std::cout << HasMethod<Test2>::value << std::endl; // prints 1
}

好的。经过一番思考,我找到了解决方案。我们可以使用declval(&T::method)将失败的事实,如果有一个以上的过载,来检测我们是否有至少一个过载,通过添加另一个。这里是解决方案。它是相当冗长,但我无法减少它。至少它的工作。

#include <iostream>
#include <type_traits>

class Test
{
};

class Test1
{
public:
    void method();
};

class Test2
{
public:
    void method();
    void method(int);
};

class Test3
{
public:
    using method = int;
};

class Test4
{
public:
    int method;
};

template<typename T, typename = void>
struct HasSingleOverload : std::false_type {};
template<typename T>
struct HasSingleOverload<T, std::void_t<decltype(&T::method)>> : std::true_type {};

template<typename T, typename = void>
struct IsMemberFunction : std::false_type {};
template<typename T>
struct IsMemberFunction<T, std::enable_if_t<std::is_member_function_pointer<decltype(&T::method)>::value>> : std::true_type {};

template<typename T, typename = void>
struct IsType : std::false_type {};
template<typename T>
struct IsType<T, std::void_t<typename T::method>> : std::true_type {};

struct HasOverload {
    void method();
};

template<typename T>
struct CheckOverload : T, HasOverload {
};

template<typename T>
using HasConflict = std::bool_constant<!HasSingleOverload<CheckOverload<T>>::value>;

template<typename T>
using HasAnyOverload = std::conditional_t<HasSingleOverload<T>::value || IsType<T>::value, IsMemberFunction<T>, HasConflict<T>>;

int main()
{
    std::cout << HasAnyOverload<Test>::value << std::endl; // prints 0
    std::cout << HasAnyOverload<Test1>::value << std::endl; // prints 1
    std::cout << HasAnyOverload<Test2>::value << std::endl; // prints 1
    std::cout << HasAnyOverload<Test3>::value << std::endl; // prints 0
    std::cout << HasAnyOverload<Test4>::value << std::endl; // prints 0
}

相关问题