Как проверить существование вызываемой функции-члена производного класса? - PullRequest
1 голос
/ 19 июня 2019

Я использую 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 Demo: 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 голосов
/ 29 июня 2019

Это не идеальный ответ, но я достигаю своей цели, вводя одно соглашение.Добавление псевдонима базового класса в качестве типа члена с конкретным именем.В моем примере имя base.

Boost.TTI проверяет только целевой класс, поэтому, если целевой класс не имеет base, он просто возвращает результат проверки функции-члена.В противном случае, если целевой класс имеет функцию-член, верните true, если он не применяет тот же процесс для типа base.

Вот полный пример:

#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.

...