0

所以我有以下(减少)类:

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基本上是一个包含一组特定类型组件的向量的包装器。

该类ComponentBlockTupleAccessor或多或少模拟了 std::tuple 的缩减版本,其中可以使用可变参数模板将任意数量的唯一类型ComponentArray继承到类中。ComponentTuple

pop_back函数 inComponentTuple旨在递归地从每个s中取出pop_back一个元素。ComponentArray

在课堂之外,ComponentTuple我希望能够简单地调用类似的东西,compTupleInstance.pop_back()并且所有ComponentArray的都应该删除它们的最后一个元素。

我得到一个编译错误“重载'pop_back()'的调用不明确”pop_back();

我似乎无法弄清楚 A、B(包)、S 和 T(包)模板参数的组合,它可以为我提供所需的功能。我在这里想念什么?

编辑:这是一个简单的使用场景:

// 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 模板参数将始终是唯一类型,并且始终大于一。

4

3 回答 3

0

核心问题:当只有一个模板参数(包可以为空)时,编译器看起来同样好template <typename S, typename ... T>template <typename S>它无法决定使用哪个重载。

解决方法:可以使用 fold 表达式(c++17 或以上)。

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

...如果像这样使用代码也会中断(即使使用上面的折叠表达式):( ComponentTuple<int, int, double>不明确的基类)。

于 2019-11-10T07:32:54.807 回答
0

感谢您的帮助,既然您已经指出,两者之间的歧义似乎很明显<typename S><typename S, typename... T>出于这个原因,似乎不可能按照我尝试的方式去做。

我最终使用 aif 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.

于 2019-11-10T08:18:21.743 回答
0

问题的副本:

    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,还是调用第二种方法?

于 2019-11-10T06:29:11.143 回答