【问题标题】:C++11 variadic template template parametersC++11 可变参数模板模板参数
【发布时间】:2012-02-15 14:41:16
【问题描述】:

保留旧问题。解决方法见下文。 这可能很简单,但仍然如此。我有以下 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 继承EventContainer 模板化typelist 中的每种类型。我可以使用 Loki:: library 来完成,但我想将 C++11 与可变参数模板一起使用。 谢谢。

解决方案 1:修复 EventStorage 模板模板问题。这将使EventStorage,多重继承所有EventContainer模板,每种Ts类型。

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. 建议的那样,我可以提供一个转发方法int EventStorage,但代价是一个额外的函数调用:

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

根据 Alexandrescu 的说法,只要参数是引用,编译器就会优化这个前向调用。 现在问题正式结束:)

【问题讨论】:

    标签: c++ template-meta-programming


    【解决方案1】:

    首先引入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;
    }
    

    这个works,你可以typedef整个Storage&lt;...&gt;位。

    编辑:关注 cmets 关于“组合”类型的可能性。

    有两种解决方案:

    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&lt;Event1,Event2&gt; pumpEvents; typedef typelist&lt;Event3,Event4,Event5&gt; displayEvents; 但是正如你所说的那样,如果存储需要同时存储它们,我想将两者结合起来typelists
    • 我编辑了我的答案以包括一个typelist 适配器和一个存储组合器。
    • 非常感谢。在我从其他人的回答评论中解决了这个模棱两可的问题后,我会尝试这样做。这很奇怪。 push() 不是过载了吗?
    • 使用继承的重载解决方案似乎并不完全直观:我的答案中的解决方案有效,但感觉很难看。
    • 这里的最佳答案是我找到的最简洁的答案:本质上,编译器会找到第一个具有正确名称的一个或多个重载的范围,然后停止查找。重载解决方案、隐式转换等应用于这组候选对象。 stackoverflow.com/questions/72010/c-overload-resolution
    【解决方案2】:

    目前,您甚至从未将类型列表实例化传递给 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-&gt;EventContainer&lt;T&gt;::push,但它需要精确的类型匹配。

    【讨论】:

    • 是的,我自己想通了。但是我现在变得模棱两可。假设添加/替换了你的修复我得到这个:error: request for member ‘push’ is ambiguouserror: candidates are: void EventContainer&lt;T&gt;::push(const T&amp;) [with T = Event2]void EventContainer&lt;T&gt;::push(const T&amp;) [with T = Event1] Main 是:` int main() { EventStorage ev;事件1 ev1; ev.push(ev1);返回0; } `
    • 是的,我没有添加推送位,但它需要一些摆弄 - 现在编辑......
    • 啊,现在我明白了,有点误会。我希望继承每个EventContainer,每个模板都使用typelist 中的每种类型进行模板化。我的代码其实是:`template class EventStorage { };模板 类 EventStorage >: public EventContainer... { }; ` 编辑:我只是不能在这里格式化 sh*t。对不起:(
    • 别担心,cmets 并不适合大量代码 :-) 只需将其编辑到问题的末尾,我会看看。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-10
    • 2016-12-01
    • 2012-08-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多