std::is_member_function_pointer not working for overloaded functions?

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

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:

  1. class Test1
  2. {
  3. public:
  4. void method();
  5. };
  6. class Test2
  7. {
  8. public:
  9. void method();
  10. void method(int);
  11. };
  12. template <typename T, typename = void>
  13. struct HasMethod : std::false_type
  14. {
  15. };
  16. template <typename T>
  17. struct HasMethod<T, std::enable_if_t<std::is_member_function_pointer<decltype(&T::method)>::value>>
  18. : std::true_type
  19. {
  20. };
  21. int main()
  22. {
  23. std::cout << HasMethod<Test1>::value << std::endl; // prints 1
  24. std::cout << HasMethod<Test2>::value << std::endl; // prints 0
  25. }

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

以下是代码部分的翻译:

  1. 要检测类成员的存在通常的方法是使用`std::void_t`模板。您可以像这样执行它:
  2. ```c++
  3. #include <iostream>
  4. #include <type_traits>
  5. class Test1
  6. {
  7. public:
  8. void method();
  9. };
  10. class Test2
  11. {
  12. public:
  13. void method();
  14. void method(int);
  15. };
  16. template <typename T, typename = void>
  17. struct HasMethod : std::false_type
  18. {
  19. };
  20. // 使用method(0)来检测void method(int)的重载
  21. // 在这种情况下,您甚至不需要std::void_t,因为method无论如何返回void,但对于任何其他返回类型,您都需要它
  22. template <typename T>
  23. struct HasMethod<T, std::void_t<decltype(std::declval<T>().method())>>
  24. : std::true_type
  25. {
  26. };
  27. int main()
  28. {
  29. std::cout << HasMethod<Test1>::value << std::endl; // 输出1
  30. std::cout << HasMethod<Test2>::value << std::endl; // 输出1
  31. }
  1. ```c++
  2. 好的。经过一些思考,我找到了解决方案。我们可以利用`declval(&T::method)`将失败的事实,如果有多于一个重载,通过添加另一个来检测我们是否至少有一个重载。以下是解决方案。它相当冗长,但我无法缩减它。至少它可以工作。
  3. ```c++
  4. #include <iostream>
  5. #include <type_traits>
  6. class Test
  7. {
  8. };
  9. class Test1
  10. {
  11. public:
  12. void method();
  13. };
  14. class Test2
  15. {
  16. public:
  17. void method();
  18. void method(int);
  19. };
  20. class Test3
  21. {
  22. public:
  23. using method = int;
  24. };
  25. class Test4
  26. {
  27. public:
  28. int method;
  29. };
  30. template<typename T, typename = void>
  31. struct HasSingleOverload : std::false_type {};
  32. template<typename T>
  33. struct HasSingleOverload<T, std::void_t<decltype(&T::method)>> : std::true_type {};
  34. template<typename T, typename = void>
  35. struct IsMemberFunction : std::false_type {};
  36. template<typename T>
  37. struct IsMemberFunction<T, std::enable_if_t<std::is_member_function_pointer<decltype(&T::method)>::value>> : std::true_type {};
  38. template<typename T, typename = void>
  39. struct IsType : std::false_type {};
  40. template<typename T>
  41. struct IsType<T, std::void_t<typename T::method>> : std::true_type {};
  42. struct HasOverload {
  43. void method();
  44. };
  45. template<typename T>
  46. struct CheckOverload : T, HasOverload {
  47. };
  48. template<typename T>
  49. using HasConflict = std::bool_constant<!HasSingleOverload<CheckOverload<T>>::value>;
  50. template<typename T>
  51. using HasAnyOverload = std::conditional_t<HasSingleOverload<T>::value || IsType<T>::value, IsMemberFunction<T>, HasConflict<T>>;
  52. int main()
  53. {
  54. std::cout << HasAnyOverload<Test>::value << std::endl; // 输出0
  55. std::cout << HasAnyOverload<Test1>::value << std::endl; // 输出1
  56. std::cout << HasAnyOverload<Test2>::value << std::endl; // 输出1
  57. std::cout << HasAnyOverload<Test3>::value << std::endl; // 输出0
  58. std::cout << HasAnyOverload<Test4>::value << std::endl; // 输出0
  59. }
  1. 这是您提供的代码的翻译。
  2. <details>
  3. <summary>英文:</summary>
  4. To detect existence of class members usual approach is to use `std::void_t` template. You can do it like this:
  5. ```c++
  6. #include &lt;iostream&gt;
  7. #include &lt;type_traits&gt;
  8. class Test1
  9. {
  10. public:
  11. void method();
  12. };
  13. class Test2
  14. {
  15. public:
  16. void method();
  17. void method(int);
  18. };
  19. template &lt;typename T, typename = void&gt;
  20. struct HasMethod : std::false_type
  21. {
  22. };
  23. // Use method(0) to detect void method(int) overload
  24. // 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
  25. template &lt;typename T&gt;
  26. struct HasMethod&lt;T, std::void_t&lt;decltype(std::declval&lt;T&gt;().method())&gt;&gt;
  27. : std::true_type
  28. {
  29. };
  30. int main()
  31. {
  32. std::cout &lt;&lt; HasMethod&lt;Test1&gt;::value &lt;&lt; std::endl; // prints 1
  33. std::cout &lt;&lt; HasMethod&lt;Test2&gt;::value &lt;&lt; std::endl; // prints 1
  34. }

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.

  1. #include &lt;iostream&gt;
  2. #include &lt;type_traits&gt;
  3. class Test
  4. {
  5. };
  6. class Test1
  7. {
  8. public:
  9. void method();
  10. };
  11. class Test2
  12. {
  13. public:
  14. void method();
  15. void method(int);
  16. };
  17. class Test3
  18. {
  19. public:
  20. using method = int;
  21. };
  22. class Test4
  23. {
  24. public:
  25. int method;
  26. };
  27. template&lt;typename T, typename = void&gt;
  28. struct HasSingleOverload : std::false_type {};
  29. template&lt;typename T&gt;
  30. struct HasSingleOverload&lt;T, std::void_t&lt;decltype(&amp;T::method)&gt;&gt; : std::true_type {};
  31. template&lt;typename T, typename = void&gt;
  32. struct IsMemberFunction : std::false_type {};
  33. template&lt;typename T&gt;
  34. 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 {};
  35. template&lt;typename T, typename = void&gt;
  36. struct IsType : std::false_type {};
  37. template&lt;typename T&gt;
  38. struct IsType&lt;T, std::void_t&lt;typename T::method&gt;&gt; : std::true_type {};
  39. struct HasOverload {
  40. void method();
  41. };
  42. template&lt;typename T&gt;
  43. struct CheckOverload : T, HasOverload {
  44. };
  45. template&lt;typename T&gt;
  46. using HasConflict = std::bool_constant&lt;!HasSingleOverload&lt;CheckOverload&lt;T&gt;&gt;::value&gt;;
  47. template&lt;typename T&gt;
  48. 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;;
  49. int main()
  50. {
  51. std::cout &lt;&lt; HasAnyOverload&lt;Test&gt;::value &lt;&lt; std::endl; // prints 0
  52. std::cout &lt;&lt; HasAnyOverload&lt;Test1&gt;::value &lt;&lt; std::endl; // prints 1
  53. std::cout &lt;&lt; HasAnyOverload&lt;Test2&gt;::value &lt;&lt; std::endl; // prints 1
  54. std::cout &lt;&lt; HasAnyOverload&lt;Test3&gt;::value &lt;&lt; std::endl; // prints 0
  55. std::cout &lt;&lt; HasAnyOverload&lt;Test4&gt;::value &lt;&lt; std::endl; // prints 0
  56. }

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:

确定