【问题标题】:Checking if a class has a function that has parameters in it检查一个类是否有一个带有参数的函数
【发布时间】:2016-05-05 15:18:25
【问题描述】:

阅读了Is it possible to write a C++ template to check for a function's existence? 的问题并测试了一些答案,我发现它仅适用于检测不带参数的函数,例如 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) };\
};

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

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

【问题讨论】:

  • 您确定要检查是否有特定签名的函数,例如void SetPosition(float,float),或者是否有函数SetPosition tak 可以将两个值隐式转换为浮点数?
  • 一个特定的签名或一个隐式可转换的版本,任何一个都可以满足我的需要。我可能可以更好地使用特定签名,因为我可以宏模板参数,尽管我愿意接受任何可以解决这个特定问题的解决方案。
  • Here's 使用检测成语的解决方案。
  • 您应该将其添加为答案。谢谢彼得。
  • here's 对您的类似 C++03 的解决方案的修改

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


【解决方案1】:

由于您要检查两者,是否存在特定签名的成员函数,以及是否可以使用某些参数类型调用给定函数,您可以使用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>{}, "!");
}

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

DEMO

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-12-12
    • 2023-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-01
    相关资源
    最近更新 更多