std::is_member_function_pointer not working for overloaded functions?

huangapple go评论62阅读模式
英文:

std::is_member_function_pointer not working for overloaded functions?

问题

我已经编写了一个特性,通过std::is_member_function_pointer来检测一个类是否具有特定的公共成员函数:

然而,似乎当函数被重载时,std::is_member_function_pointer无法检测到它,如Test2所示。是否有办法使它能够在方法被重载时正常工作?

英文:

I've written a trait that detects whether a class has a certain public member function via 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
}

However it seems that when the function is overloaded, then std::is_member_function_pointer is not able to detect it, as shown with Test2.
Is there a way to make it work regardless of whether the method is overloaded?

答案1

得分: 1

以下是代码部分的翻译:

要检测类成员的存在通常的方法是使用`std::void_t`模板。您可以像这样执行它:
```c++
#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
{
};

// 使用method(0)来检测void method(int)的重载
// 在这种情况下,您甚至不需要std::void_t,因为method无论如何返回void,但对于任何其他返回类型,您都需要它
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; // 输出1
    std::cout << HasMethod<Test2>::value << std::endl; // 输出1
}

```c++
好的。经过一些思考,我找到了解决方案。我们可以利用`declval(&T::method)`将失败的事实,如果有多于一个重载,通过添加另一个来检测我们是否至少有一个重载。以下是解决方案。它相当冗长,但我无法缩减它。至少它可以工作。
```c++
#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; // 输出0
    std::cout << HasAnyOverload<Test1>::value << std::endl; // 输出1
    std::cout << HasAnyOverload<Test2>::value << std::endl; // 输出1
    std::cout << HasAnyOverload<Test3>::value << std::endl; // 输出0
    std::cout << HasAnyOverload<Test4>::value << std::endl; // 输出0
}
这是您提供的代码的翻译。

<details>
<summary>英文:</summary>

To detect existence of class members usual approach is to use `std::void_t` template. You can do it like this:
```c++
#include &lt;iostream&gt;
#include &lt;type_traits&gt;

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

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

template &lt;typename T, typename = void&gt;
struct HasMethod : std::false_type
{
};

// Use method(0) to detect void method(int) overload
// You don&#39;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 &lt;typename T&gt;
struct HasMethod&lt;T, std::void_t&lt;decltype(std::declval&lt;T&gt;().method())&gt;&gt;
    : std::true_type
{
};

int main()
{
    std::cout &lt;&lt; HasMethod&lt;Test1&gt;::value &lt;&lt; std::endl; // prints 1
    std::cout &lt;&lt; HasMethod&lt;Test2&gt;::value &lt;&lt; std::endl; // prints 1
}

Ok. After some thinking I found solution. We can use fact that declval(&amp;T::method) will fail, if there is more than one overload, to detect if we have at least one overload, by adding another one. Here is solution. It is quite verbose, but I was unable to reduce it. At least it works.

#include &lt;iostream&gt;
#include &lt;type_traits&gt;

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&lt;typename T, typename = void&gt;
struct HasSingleOverload : std::false_type {};
template&lt;typename T&gt;
struct HasSingleOverload&lt;T, std::void_t&lt;decltype(&amp;T::method)&gt;&gt; : std::true_type {};

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

template&lt;typename T, typename = void&gt;
struct IsType : std::false_type {};
template&lt;typename T&gt;
struct IsType&lt;T, std::void_t&lt;typename T::method&gt;&gt; : std::true_type {};

struct HasOverload {
    void method();
};

template&lt;typename T&gt;
struct CheckOverload : T, HasOverload {
};

template&lt;typename T&gt;
using HasConflict = std::bool_constant&lt;!HasSingleOverload&lt;CheckOverload&lt;T&gt;&gt;::value&gt;;

template&lt;typename T&gt;
using HasAnyOverload = std::conditional_t&lt;HasSingleOverload&lt;T&gt;::value || IsType&lt;T&gt;::value, IsMemberFunction&lt;T&gt;, HasConflict&lt;T&gt;&gt;;

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

huangapple
  • 本文由 发表于 2023年2月18日 02:10:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/75487883.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定