Использование шаблона для определения размера std :: array CRTP - PullRequest
0 голосов
/ 03 ноября 2018

У меня есть чисто виртуальная функция, которая возвращает std :: array в базовом классе. Я хочу, чтобы размер этого массива зависел от типа в производном классе. Я пробовал следующее, но кажется, что компилятор не может разрешить шаблоны из-за неполного типа.

template<typename T>
struct base
{
    virtual std::array<int, T::SIZE> foo(void) = 0;
};

struct derived : public base<derived>
{
    enum 
    {
        SIZE = 5
    };
    std::array<int, derived::SIZE> foo(void) 
    {
        return std::array<int, derived::SIZE>{1,2,3,4,5};
    };
};

В экземпляре 'struct base': 12:25: требуется отсюда 9:38: ошибка: неполный тип «производный», используемый в описателе вложенного имени

Я также пытался сделать что-то вроде черты типа, но я снова получаю неполный тип, что в этом случае имеет смысл, поскольку специализация шаблона требует, чтобы класс был фактически завершен, прежде чем он сможет завершить специализацию.

template<typename T>
struct sizeTrait;

template<typename T>
struct base
{
    virtual std::array<int, sizeTrait<T>::SIZE> foo(void) = 0;
};

struct derived : public base<derived>
{
    std::array<int, sizeTrait<derived>::SIZE> foo(void) 
    {
        return std::array<int, sizeTrait<derived>::SIZE>{1,2,3,4,5};
    };
};

template<>
struct sizeTrait<derived>
{
    enum
    {
        SIZE = 5
    };
};

Кто-нибудь имеет представление о том, как добиться чего-то подобного? Я не хочу прибегать к использованию макросов, если это возможно. Я планирую иметь много разных типов производных классов, которые все наследуют базовый класс, но foo будет возвращать разные размеры std :: array в зависимости от перечисления (или некоторого другого типа), определенного в их собственном классе. Кроме того, я знаю, что могу использовать std :: vector, но я хотел бы сделать это с помощью массива, поскольку размер вывода уже определен.

EDIT:

Было предложено использовать параметр шаблона в базе для определения размера массива.

#include <array>

template<typename T, size_t S>
struct base
{
    using array_type = std::array<int, S>;
    virtual array_type foo() = 0;
};

struct derived : public base<derived, 5>
{
    array_type foo() override
    {
        return array_type {1, 2, 3, 4, 5};
    };
};

Тем не менее, у меня есть другой шаблонный класс, который принимает производную в качестве аргумента шаблона, и он должен иметь массив того же размера.

template<typename DerivedClass>
struct other
{
    std::array<int, DerivedClass::SIZE> array_;
};

В этом случае я бы хотел, чтобы размер array_ определялся на основе того, чем фактически является DerivedClass. Есть ли способ решить, что DerviedClass :: SIZE было 5? Может быть, получить доступ к базе через параметр шаблона DerivedClass, как DerivedClass :: base :: array_type?

Ответы [ 2 ]

0 голосов
/ 03 ноября 2018

В вашей попытке sizeTrait вам просто нужно переместить определение до использования в derived. Это достигается с помощью предварительной декларации derived:

template<typename T>
struct sizeTrait;

template<typename T>
struct base
{
    virtual std::array<int, sizeTrait<T>::SIZE> foo(void) = 0;
};

struct derived;

template<>
struct sizeTrait<derived>
{
    enum
    {
        SIZE = 5
    };
};

struct derived : public base<derived>
{
    std::array<int, sizeTrait<derived>::SIZE> foo(void) 
    {
        return std::array<int, sizeTrait<derived>::SIZE>{1,2,3,4,5};
    }
};
0 голосов
/ 03 ноября 2018

Почему бы не сделать размер параметром шаблона на базе?

#include <array>

template<typename T, size_t S>
struct base
{
    using array_type = std::array<int, S>;
    virtual array_type foo() = 0;
};

struct derived : public base<derived, 5>
{
    array_type foo() override
    {
        return array_type {1, 2, 3, 4, 5};
    }
};

Обновление для ответа на вопрос о получении доступа к типу массива (или размеру) из классов с использованием derived. Вы можете просто получить доступ к типу:

template<class T>
struct another
{
    using array_type = typename T::array_type;

    array_type bar()
    {
        return array_type {1, 2, 3, 4, 5};
    }

    static constexpr size_t size()
    {
        // Returns 5
        return std::tuple_size<array_type>();
    }
};
...