如何检查派生类的可调用成员函数的存在?

时间:2019-06-19 08:45:35

标签: c++ boost introspection typetraits member-functions

我正在使用Boost.TTI检查成员函数的存在。我不仅要检查现有功能,还要检查不存在的功能。

Boost.TTI似乎不适用于派生类,即使我使用using目标成员函数也是如此。

#include <boost/tti/has_member_function.hpp>

BOOST_TTI_HAS_MEMBER_FUNCTION(func1);
BOOST_TTI_HAS_MEMBER_FUNCTION(func2);

struct base {
    void func1() {}
};

struct derived : base {
};

struct derived_using : base {
    using base::func1;
};

int main() {
    static_assert( has_member_function_func1<base, void>::value);
    static_assert(!has_member_function_func2<base, void>::value);

    static_assert( has_member_function_func1<derived, void>::value); // error
    static_assert(!has_member_function_func2<derived, void>::value);

    static_assert( has_member_function_func1<derived_using, void>::value); // error
    static_assert(!has_member_function_func2<derived_using, void>::value);
}

Runnin演示:https://wandbox.org/permlink/5XkyCoeo0xEGVm3M

我要检查成员函数,而不要检查名称为func1 func2等任何元素(类型,变量)。

我也尝试了std::is_invocable。它可以像我期望的那样用于派生类,但是对于不存在的函数会发生编译错误。

#include <type_traits>

struct base {
    void func1() {}
};

struct derived : base {
};

int main() {
    static_assert( std::is_invocable<decltype(&base::func1), base>::value);
    static_assert(!std::is_invocable<decltype(&base::func2), base>::value);

    static_assert( std::is_invocable<decltype(&derived::func1), derived>::value);
    static_assert(!std::is_invocable<decltype(&derived::func2), derived>::value);
}

正在运行的演示:https://wandbox.org/permlink/3v9H0CFVxPnfGj3t

有没有什么好方法可以检查既支持派生类又支持不存在成员函数的成员函数是否存在。

1 个答案:

答案 0 :(得分:0)

这不是一个完美的答案,但是我实现了引入一个约定的目标。 将基类别名添加为具有特定名称的成员类型。在我的示例中,名称为base

Boost.TTI仅检查目标类,因此,如果目标类没有base,则只需返回成员函数检查的结果。否则,如果目标类具有成员函数,则如果目标类没有为base类型应用相同的过程,则返回true。

以下是完整的示例:

#include <utility>

#include <boost/tti/has_member_function.hpp>
#include <boost/tti/has_type.hpp>

BOOST_TTI_HAS_TYPE(base);

BOOST_TTI_HAS_MEMBER_FUNCTION(func1);
BOOST_TTI_HAS_MEMBER_FUNCTION(func2);

struct b1 {
    void func1() {}
};

struct b2 {
};

struct d1 : b1 {
    using base = b1; // This convention is required
};

struct d2 : b2 {
    using base = b2;
    void func1() {}
};

template <template <typename...> typename Func, typename T, typename... Params>
constexpr bool recursive_apply() {
    if constexpr(has_type_base<T>::value) {
        return
            Func<T, Params...>::value ||
            recursive_apply<Func, typename T::base, Params...>();
    }
    else {
        return Func<T, Params...>::value;
    }
}

int main() {
    static_assert( recursive_apply<has_member_function_func1, b1, void>());
    static_assert( recursive_apply<has_member_function_func1, d1, void>());

    static_assert(!recursive_apply<has_member_function_func2, b1, void>());
    static_assert(!recursive_apply<has_member_function_func2, d1, void>());

    static_assert(!recursive_apply<has_member_function_func1, b2, void>());
    static_assert( recursive_apply<has_member_function_func1, d2, void>());
}

正在运行的演示:https://wandbox.org/permlink/IFFzenEFWX4GY8OD

我使用C ++ 17功能if constexpr。我试图用SFINAE将其替换为模板部分指定。但是到目前为止,我做不到。问题是模板模板参数不能在局部专业化中推导。

此答案适用于C ++ 17和一个约定base