Рекурсивная функция, действующая на параметры шаблона класса variadic - PullRequest
0 голосов
/ 10 ноября 2019

Итак, у меня есть следующие (урезанные) классы:

template <typename A, typename... B>
struct ComponentTupleAccessor: 
    public ComponentArray<A>, 
    public ComponentTupleAccessor<B...> 
{
    ComponentTupleAccessor(const uint32_t capacity): 
        ComponentArray<A>(capacity), 
        ComponentTupleAccessor<B...>(capacity) 
    {}
};
template <typename A>
struct ComponentTupleAccessor<A>: 
    public ComponentArray<A> 
{
    ComponentTupleAccessor<A>(const uint32_t capacity): 
        ComponentArray<A>(capacity) 
    {}
};
template <typename A, typename ...B>
class ComponentTuple {
    ComponentTupleAccessor<A, B...> m_Components;
    uint32_t m_Capacity;

public:
    ComponentTuple(const RB32u capacity): 
        m_Capacity{capacity}, 
        m_Components(capacity) 
    {}

    template <typename S, typename ...T>
    void pop_back() {
        m_Components.Component<S>::pop_back();
        pop_back<T...>();
    }

    template <typename S>
    void pop_back() {
        m_Components.Component<S>::pop_back();
    }

    void pop_back() {
        pop_back<A, B...>();
    }
};

Класс ComponentArray - это, по сути, оболочка для вектора, который содержит несколько компонентов определенногоtype.

Класс ComponentBlockTupleAccessor более или менее эмулирует урезанную версию std :: tuple, где любое количество уникальных типов ComponentArray может быть унаследовано в классе ComponentTuple с использованием шаблонов переменных.

Функция pop_back в ComponentTuple предназначена для рекурсивного pop_back элемента от каждого из ComponentArray s.

За пределами класса ComponentTuple, который я быхотелось бы просто вызывать что-то вроде compTupleInstance.pop_back(), и у всех ComponentArray должны быть удалены последние элементы.

Я получаю ошибку компиляции "вызов перегруженного pop_back () 'неоднозначен" pop_back();

Кажется, я не могу определить комбинацию параметров шаблона A, B (pack), S и T (pack), которая дает мне необходимую функциональность. Что мне здесь не хватает?

Редактировать: Вот простой сценарий использования:

// ComponentTuple contains an int and a float ComponentArray with capacity 8.
ComponentTuple<int, float> dut(8);

// Push a set of new components to the ComponentArrays.
// This function has a similar structure to that of pop_back.
dut.push_back({8}, {3.141f});
// Another one
dut.push_back({4}, {2.718f});

// Remove the last element from all of the ComponentArrays.
dut.pop_back();

Параметры шаблона ComponentTuple всегда будут уникальными типами, и их всегда будет больше единицы.

Ответы [ 3 ]

0 голосов
/ 10 ноября 2019

Основная проблема: template <typename S, typename ... T> и template <typename S> выглядят одинаково хорошо для компилятора, когда есть только один аргумент шаблона (пакет может быть пустым). Он не может принять решение о том, какую перегрузку использовать.

Решение: Вы можете использовать выражение сгиба (c ++ 17 или выше).

void pop_back() {
    (m_Components.ComponentArray<A>::pop_back(), ... , m_Components.ComponentArray<B>::pop_back());
}

... Также код ломается (даже с выражением сгиба выше), если используется так: ComponentTuple<int, int, double> (неоднозначный базовый класс).

0 голосов
/ 10 ноября 2019

Спасибо за вашу помощь, ребята, неопределенность между <typename S> и <typename S, typename... T> кажется очевидной теперь, когда вы на это указали. Кажется, по этой причине просто невозможно сделать это так, как я пытался.

В итоге я использовал if constexpr, чтобы проверить, соответствует ли рекурсия последнему типу, поэтому я могу завершитьрекурсия в этой точке. Мне это нравится еще больше, поскольку в шаблоне pop_back нет риска дать параметры шаблона, которые не использовались при объявлении класса. Например,

ComponentTuple<int, float> dut(8);

push_back<Banana, char>; // Not int, float so should cause compile error.

Используя метод constexpr, я могу приватизировать функцию pop_back (см. pop_back_ ниже) и предоставлять только версию без параметров, чтобы метод мог вызываться только вправильный путь:

template <typename A, typename ...B>
class ComponentTuple {
    ComponentTupleAccessor<A, B...> m_Components;
    uint32_t m_Capacity;

    template <typename S, typename... T>
    void pop_back_() {
        m_Components.ComponentBlock<S>::pop_back();

        if constexpr (sizeof...(T) > 0) {
            pop_back_<T...>();
        }
    }

public:
    ComponentTuple(const RB32u capacity): 
        m_Capacity{capacity}, 
        m_Components(capacity) 
    {}

    void pop_back() {
        pop_back_<A, B...>();
    }
};

Очевидно, мне нужно убедиться, что я использую по крайней мере c ++ 17 для использования if constexpr.

0 голосов
/ 10 ноября 2019

Копия вопроса:

    template <typename S, typename ...T>  // T can be empty
    void pop_back() {
        m_Components.Component<S>::pop_back();
        pop_back<T...>();
    }

    template <typename S>
    void pop_back() {
        m_Components.Component<S>::pop_back();
    }

Если я призываю pop_back<A>(), у меня есть S = A. Но я называю первый метод с T пустым, или я вызываю второй метод?

...