检查类是否具有包含参数的函数

时间:2016-05-05 15:18:25

标签: c++ function class c++11 member

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) };\
};

如何修改上面的代码以检测类中包含参数的成员函数,EG void SetPosition(float,float)?

我愿意接受完全重写的解决方案,但如果任何解决方案比上述更复杂,请尝试尽可能深入地解释发生的事情,以便我(以及可能是其他人)能够理解它是如何理解的作品。对待我,就像我不知道你写的是什么意思。

1 个答案:

答案 0 :(得分:2)

由于您要检查两者,是否存在特定签名的成员函数,以及是否可以使用某些参数类型调用给定函数,您可以使用detection idiom:< / p>

#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>{}, "!");
}

注意与类B的区别,而第一个特征拒绝此类,第二个特征评估为真。

DEMO