C++11 可变参模板模板参数

6

保留旧问题。请参见以下解决方案。 这可能是一些简单的东西,但仍然存在问题。我有以下C++11代码片段:

#include <vector>

template <typename... Ts>
struct typelist
{
};

template <typename T>
struct EventContainer
{
    typedef T Type;
    /// TODO. Ring buffer
    std::vector<T> container;

    void push(const T& t)
    {
        EventContainer<T>::container.push_back(t);
    }

    virtual ~EventContainer()
    {
    }
};


template <template <typename...> class TL>
class EventStorage:
        public EventContainer<Ts>...
{

};

class Event1
{
};

class Event2
{
};

typedef typelist<Event1,Event2> Events12;

int main()
{
    EventStorage<Events12> ev;

    return 0;
}

我该如何让 EventStorage 继承 typelist 中每个类型所模板化的 EventContainer 呢?我知道可以使用 Loki 库,但我想使用 C++11 的可变参数模板来实现。 谢谢。
解决方案1:修复 EventStorage 模板模板问题。这将使得 EventStorage 多重继承所有用 Ts 模板化的 EventContainer 类型。
template <typename...>
class EventStorage
{
};

template <typename... Ts>
class EventStorage < typelist<Ts...> >:
        public EventContainer<Ts>...
{

};

现在我遇到了编译时错误,出现在以下的main()函数中:

int main()
{
    EventStorage<Events12> ev;
    Event1 ev1;
    ev.push(ev1);

    return 0;
}

In function ‘int main()’:
error: request for member ‘push’ is ambiguous
error: candidates are: void EventContainer<T>::push(const T&) [with T = Event2]
error: void EventContainer<T>::push(const T&) [with T = Event1]

为什么编译器会混淆?毕竟我使用了特定类型的推送。这里是GCC 4.6.1。

解决方案2: 正如@Matthieu M.建议的那样,我可以在EventStorage中提供一个转发方法,但这将付出一个额外的函数调用的代价:

template <typename T>
void push(const T& t)
{
    EventContainer<T>::push(t);
}

据Alexandrescu所说,只要参数是引用,编译器就会优化这个前向调用。现在问题已经正式关闭 :)
2个回答

6

首先引入 typelist 有什么意义呢?

template <typename T> struct Template { void push(T) {} };

template <typename... Args>
class Storage: public Template<Args>...
{
public:
  // forwarding...
  template <typename T>
  void push(T t) {
    Template<T>& me = *this;
    me.push(t);
  }
};

int main() {
  Storage< int, char > storage;
}

这个例子可行,你可以typedef整个Storage<...>部分。

编辑:根据有关“合并”类型的评论,以下是两种解决方案:

第一种方法:

template <typename...> struct CombineStorage;

template <typename... A, typename... B>
struct CombineStorage<Storage<A...>, Storage<B...>> {
  typedef Storage<A..., B...> type;
};

或者提供一个类型列表适配器:

template <typename... Args>
class Storage<typelist<Args...>>: public Storage<Args...> {};

我希望我能够将不同类型的“事件(Event)”排列组合成颗粒大小。例如, typedef typelist<Event1,Event2> pumpEvents; typedef typelist<Event3,Event4,Event5> displayEvents; 但是按照您所说的方式,如果需要同时存储它们两个,我想要将这两个“类型列表(typelists)”组合起来。 - Dragomir Ivanov
我编辑了我的答案,包括一个 typelist 适配器和一个存储组合器。 - Matthieu M.
非常感谢。在解决其他答案评论中的歧义问题后,我会尝试这个方法。这很奇怪。push()不是被重载了吗? - Dragomir Ivanov
重载解析与继承似乎并不完全直观:我的答案中的解决方案有效,但感觉有些丑陋。 - Useless
1
这里的最佳答案是我找到的最简洁的答案:实际上,编译器会找到第一个具有一个或多个正确名称重载的作用域,并停止查找。重载解析、隐式转换等仅应用于此候选集合。https://dev59.com/PnVD5IYBdhLWcg3wJIEK - Useless
显示剩余2条评论

1

目前,您甚至没有将类型列表实例传递给EventStorage,只有类型列表模板。因此,当前不存在要扩展的类型包。

但是,您应该能够通过专业化来解压缩类型列表,并以其他方式处理类型包:

template <typename...> class EventStorage;

template <typename Head, typename... Tail> class EventStorage<Head, Tail...>
  : public EventContainer<Head>, EventStorage<Tail...>
{
  using EventContainer<Head>::push;
  using EventStorage<Tail...>::push;
};

// allows you to pass typelists for convenience
template <typename... TL> class EventStorage<typelist<TL...>>
  : public EventStorage<TL...>
{
  using EventStorage<TL...>::push;
};

using声明只是将所有push方法都放入同一重载集中,这对我来说似乎很有效。

另一种选择是添加一个模板方法(可能只是针对顶层类型列表特化),该方法明确地转发到this->EventContainer<T>::push,但它需要精确的类型匹配。


是的,我刚刚自己解决了。但是现在我遇到了歧义。假设我添加/替换了您的修复,我会得到以下内容:error: request for member ‘push’ is ambiguouserror: candidates are: void EventContainer<T>::push(const T&) [with T = Event2]void EventContainer<T>::push(const T&) [with T = Event1]主要代码如下: ` int main() { EventStorage<Events12> ev; Event1 ev1; ev.push(ev1); return 0; } ` - Dragomir Ivanov
是的,我没有添加推送位,但需要稍微调整一下 - 现在正在编辑... - Useless
啊,现在我明白了有一点误解。 我想要继承每个用typelist中的每种类型模板化的EventContainer。我的代码实际上是:template class EventStorage { }; template class EventStorage> : public EventContainer... { }; - Dragomir Ivanov
不用担心,注释并不适合大量的代码 :-) 只需将其编辑到您的问题末尾,我会看一下。 - Useless

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接