检查 class 是否有包含参数的函数
Checking if a class has a function that has parameters in it
阅读 Is it possible to write a C++ template to check for a function's existence? 的问题并测试了一些答案后,我发现它只适用于检测不带参数的函数,EG void HelloWord()。四处寻找答案要么只是给出无参数函数的解决方案,要么是令人眼花缭乱的复杂解决方案,我无法弄清楚。
这是我构建检测器的宏模板代码:
#define MEMBERFUNCTIONTODETECT(CONTAINS_NAME,MEMBERFUNCTION) \
template <typename TemplateItem>\
class CONTAINS_NAME\
{\
typedef char Yes;\
typedef char No[2];\
\
template <typename TemplateClass> static Yes &Test( decltype(&TemplateClass::MEMBERFUNCTION) );\
template <typename TemplateClass> static No &Test(...);\
\
public:\
enum { Value = sizeof(Test<TemplateItem>(0)) == sizeof(char) };\
};
如何修改上述代码以检测 class 中包含参数 EG void SetPosition(float,float) 的成员函数?
我愿意接受完全重写的解决方案,但如果有任何解决方案比上述更复杂,请尝试尽可能深入地解释正在发生的事情,以便我(可能还有其他人)能够理解怎么运行的。对待我就像我不知道你写的是什么意思。
既然你想检查两者,是否有一个特定签名的成员函数,以及一个给定的函数是否可以用某些参数类型调用,你可以使用 detection idiom:
#include <type_traits>
#include <utility>
template <typename...>
using void_t = void;
template <typename AlwaysVoid, template <typename...> class Operation, typename... Args>
struct detect_impl : std::false_type {};
template <template <typename...> class Operation, typename... Args>
struct detect_impl<void_t<Operation<Args...>>, Operation, Args...> : std::true_type {};
template <template <typename...> class Operation, typename... Args>
using detect = detect_impl<void_t<>, Operation, Args...>;
现在您只需要添加一些自定义检测器:
// Check specific signature
template <typename T, typename Sig>
using has_SetPosition = decltype(static_cast<Sig>(&T::SetPosition));
// Check if the function can be called with Args...
template <typename T, typename... Args>
using can_call_SetPosition = decltype(std::declval<T>().SetPosition(std::declval<Args>()...));
测试:
struct A
{
void SetPosition(float, float) {}
};
struct B
{
void SetPosition(int, int) {}
};
struct C
{
};
int main()
{
static_assert(detect<has_SetPosition, A, void(A::*)(float, float)>{}, "!");
static_assert(!detect<has_SetPosition, B, void(B::*)(float, float)>{}, "!");
static_assert(!detect<has_SetPosition, C, void(C::*)(float, float)>{}, "!");
static_assert(detect<can_call_SetPosition, A&, float, float>{}, "!");
static_assert(detect<can_call_SetPosition, B&, float, float>{}, "!");
static_assert(!detect<can_call_SetPosition, C&, float, float>{}, "!");
}
注意与 class B
的区别,而第一个特征拒绝此 class,第二个特征评估为真。
阅读 Is it possible to write a C++ template to check for a function's existence? 的问题并测试了一些答案后,我发现它只适用于检测不带参数的函数,EG void HelloWord()。四处寻找答案要么只是给出无参数函数的解决方案,要么是令人眼花缭乱的复杂解决方案,我无法弄清楚。
这是我构建检测器的宏模板代码:
#define MEMBERFUNCTIONTODETECT(CONTAINS_NAME,MEMBERFUNCTION) \
template <typename TemplateItem>\
class CONTAINS_NAME\
{\
typedef char Yes;\
typedef char No[2];\
\
template <typename TemplateClass> static Yes &Test( decltype(&TemplateClass::MEMBERFUNCTION) );\
template <typename TemplateClass> static No &Test(...);\
\
public:\
enum { Value = sizeof(Test<TemplateItem>(0)) == sizeof(char) };\
};
如何修改上述代码以检测 class 中包含参数 EG void SetPosition(float,float) 的成员函数?
我愿意接受完全重写的解决方案,但如果有任何解决方案比上述更复杂,请尝试尽可能深入地解释正在发生的事情,以便我(可能还有其他人)能够理解怎么运行的。对待我就像我不知道你写的是什么意思。
既然你想检查两者,是否有一个特定签名的成员函数,以及一个给定的函数是否可以用某些参数类型调用,你可以使用 detection idiom:
#include <type_traits>
#include <utility>
template <typename...>
using void_t = void;
template <typename AlwaysVoid, template <typename...> class Operation, typename... Args>
struct detect_impl : std::false_type {};
template <template <typename...> class Operation, typename... Args>
struct detect_impl<void_t<Operation<Args...>>, Operation, Args...> : std::true_type {};
template <template <typename...> class Operation, typename... Args>
using detect = detect_impl<void_t<>, Operation, Args...>;
现在您只需要添加一些自定义检测器:
// Check specific signature
template <typename T, typename Sig>
using has_SetPosition = decltype(static_cast<Sig>(&T::SetPosition));
// Check if the function can be called with Args...
template <typename T, typename... Args>
using can_call_SetPosition = decltype(std::declval<T>().SetPosition(std::declval<Args>()...));
测试:
struct A
{
void SetPosition(float, float) {}
};
struct B
{
void SetPosition(int, int) {}
};
struct C
{
};
int main()
{
static_assert(detect<has_SetPosition, A, void(A::*)(float, float)>{}, "!");
static_assert(!detect<has_SetPosition, B, void(B::*)(float, float)>{}, "!");
static_assert(!detect<has_SetPosition, C, void(C::*)(float, float)>{}, "!");
static_assert(detect<can_call_SetPosition, A&, float, float>{}, "!");
static_assert(detect<can_call_SetPosition, B&, float, float>{}, "!");
static_assert(!detect<can_call_SetPosition, C&, float, float>{}, "!");
}
注意与 class B
的区别,而第一个特征拒绝此 class,第二个特征评估为真。