英文:
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 <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
}
Ok. After some thinking I found solution. We can use fact that declval(&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 <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
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论