检查 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,第二个特征评估为真。

DEMO