模板模板参数与可变模板

Template template parameters with variadic templates

本文关键字:参数      更新时间:2023-10-16

为了清晰起见,我删除了构造函数&析构函数等,它们不会向问题中添加任何内容。我有一个基类,用来为派生模板类创建一个公共祖先。

class PeripheralSystemBase {
public:
    virtual void someFunctionThatsCommonToAllPeripherals() {}
};
template <class T, uint32_t numPeripherals = 1>
class PeripheralSystem : public PeripheralSystemBase {
public:
    PeripheralSystem() : vec(T) {}
    std::vector<T> vec;  // different types of T is the reason why I need to template this class
};
// A & B declaration & definition are irrelevant here
class A{};
class B{};
// There are multiple different derived variants of PeripheralSystem
// At the moment, each has different template parameters
template <uint32_t customisableParam1>
class DerivedSystem1 : public PeripheralSystem<A, 1> {
public:
    DerivedSystem1() : PeripheralSystem<A, 1>() {}
};
template <uint32_t customisableParam1, uint8_t customisableParam2>
class DerivedSystem2 : public PeripheralSystem<B, 1> {
public:
    DerivedSystem2() : PeripheralSystem<B, 1>() {/*maybe use customisableParam2 here */}
};

所以现在我有两个模板类,每个都派生自同一个祖先类,一个包含包含a类型的向量,另一个包含B类型的向量;每个模板都有不同的模板参数。到目前为止,一切顺利。

现在回答问题。我想能够创建一个容器模板包含一个,一个或多个派生版本的PeripheralSystem在它里面,我想我可能能够使用可变模板来做到这一点,但我有一点卡住在语法在过去的一天左右。在编译时,我希望能够创建容器类的实例。比如:

template< template<typename ...> class args...>
class ContainerClass {
  public:
    ContainerClass() : container({args}) {}
    std::vector<PeripheralSystem> container;
};
// possible usage
ContainerClass<DerivedSystem1<1>> cc1;
ContainerClass<DerivedSystem2<2, 3>> cc2;
ContainerClass<DerivedSystem1<1>, DerivedSystem2<2, 3>> cc3;

我知道我使用的可变格式是不正确的,因为我得到:

错误:期望','或'>'在template-parameter-list template<模板类参数…>>

我想告诉编译器的是,我想为模板提供一个可变数量的模板类型参数,每个模板类型参数都有一个可变数量的模板参数。我能做到这一点与可变模板请?对正确的语法有什么建议吗?

你把省略号放错地方了。试一试:

template<template<typename...> class... Args>
                                    ^^^ here

然而,你实际上并不需要模板模板参数;因为DerivedSystem1<1>是一个类型,而不是模板,所以您只需要普通的typename参数:

template<typename... Args>
class ContainerClass {

对于实际的容器,您不能使用vector<PeripheralSystem>,因为它是同构的,并且会将派生类型切割为PeripheralSystem。如果向PeripheralSystem添加虚拟析构函数,则可以使用vector<unique_ptr<PeripheralSystem>>:

template<typename... Args>
class ContainerClass {
  public:
    ContainerClass() : container{std::make_unique<Args>()...} {}
    std::vector<std::unique_ptr<PeripheralSystem>> container;
};

然而,tuple也会工作得很好,并导致更少的分配:

template<typename... Args>
class ContainerClass {
  public:
    ContainerClass() : container{Args{}...} {}
    std::tuple<Args...> container;
};