Доступ к функциям производного класса crtp из базовых вызовов - PullRequest
1 голос
/ 16 октября 2019

Мне нужно иметь доступ к статическому методу производного класса из базового класса CRTP. Есть ли способ, которым я могу достичь этого?

Вот пример кода:

#define REQUIRES(...) std::enable_if_t<(__VA_ARGS__), bool> = true
template<typename Derived>
struct ExpressionBase {
    Derived& derived() { return static_cast<Derived&>(*this); }
    const Derived& derived() const { return static_cast<const Derived&>(*this); }

    constexpr static int size()
    {
        return Derived::size();
    }

    template<typename T, REQUIRES(size() == 1)>
    operator T() const;
};

struct Derived : public ExpressionBase<Derived>
{
    constexpr static int size()
    {
        return 1;
    }
};

1 Ответ

3 голосов
/ 17 октября 2019

Вывод из ExpressionBase<Derived> включает в себя создание экземпляра ExpressionBase<Derived>, поэтому включает в себя объявление сущности

template<typename T, REQUIRES(size() == 1)>
operator T() const;

Здесь std::enable_if_t получил аргумент шаблона, который является некорректно сформированным (потому что Derived еще не завершено). Правило SFINAE здесь не применяется, поскольку некорректно сформированное выражение не находится в прямом контексте типа аргумента шаблона, поэтому оно рассматривается как серьезная ошибка.

Для того, чтобы сделатьплохое образование происходит в непосредственном контексте, используйте следующий код:

#include <type_traits>

template <bool B, class T>
struct lazy_enable_if_c {
    typedef typename T::type type;
};

template <class T>
struct lazy_enable_if_c<false, T> {};

template <class Cond, class T> 
struct lazy_enable_if : public lazy_enable_if_c<Cond::value, T> {};

template <class T>
struct type_wrapper {
    using type = T;
};

#define REQUIRES(...) std::enable_if_t<(__VA_ARGS__), bool> = true
template<typename Derived>
struct ExpressionBase {
    Derived& derived() { return static_cast<Derived&>(*this); }
    const Derived& derived() const { return static_cast<const Derived&>(*this); }

    struct MyCond {
        static constexpr bool value = Derived::size() == 1;
    };

    template<typename T, typename = typename lazy_enable_if<MyCond, type_wrapper<T>>::type>
    operator T () const {
        return T{};
    }
};

struct Derived : public ExpressionBase<Derived>
{
    constexpr static int size() {
        return 1;
    }
};

int main() {
    Derived d;
    int i = d;
    return 0;
}

Он фактически адаптирован из boost, подробности которого вы можете найти здесь .

...