【问题标题】:Writing a template that can use a std::vector or a std::set编写可以使用 std::vector 或 std::set 的模板
【发布时间】:2013-03-22 15:48:04
【问题描述】:

我编写了一个异步作业队列类,该类已经运行良好多年了。它使用std::vector 作为底层集合来保存作业,然后按照您的预期稍后处理它们。当我添加作业时,它会在此 vector 上执行 push_back

最近我决定要模板化它使用的底层集合类型以及我编写它的方式,这应该非常简单。现在这样声明:

template<typename J, typename CollectionT = std::vector<J>>
class async_jobqueue
{
public:

只有一个障碍,对于矢量类型的容器,我想将内容推到集合的末尾并调用push_back,对于设置类型的容器,我想调用insert。我怎样才能做出关于调用哪个编译的决定?或者有没有我可以使用的方便的适配器?

【问题讨论】:

  • 看看这个:stackoverflow.com/questions/257288/…。当我读到它时,它让我大吃一惊。
  • @SirPentor 这很酷,尽管它看起来可以让我在运行时弄清楚它。
  • 要么使用SFIANE(en.wikipedia.org/wiki/SFINAE),要么使用specialize或template。
  • @Benj 你可以结合std::enable_ifstatic_asset在编译时使用。
  • @Benj 你如何决定什么是矢量或固定类型的容器?您是指序列容器还是关联容器?

标签: c++ templates


【解决方案1】:

我宁愿使用重载的辅助函数。下面的一个依赖于这样一个事实,即没有标准容器同时公开单参数 insert() 函数和 push_back() 函数:

#include <utility>

template<typename C, typename T>
auto insert_in_container(C& c, T&& t) ->
    decltype(c.push_back(std::forward<T>(t)), void())
{
    c.push_back(std::forward<T>(t));
}

template<typename C, typename T>
auto insert_in_container(C& c, T&& t) ->
    decltype(c.insert(std::forward<T>(t)), void())
{
    c.insert(std::forward<T>(t));
}

这是你将如何使用它们:

#include <set>
#include <vector>
#include <iostream>

int main()
{
    std::set<int> s;
    std::vector<int> v;

    insert_in_container(s, 5);
    insert_in_container(v, 5);

    std::cout << s.size() << " " << v.size();
}

这是live example

【讨论】:

  • 你是不是这样用is_same来诱导SFINAE?
  • @David:是的,这只是一个技巧。当然还有其他方法
  • 也许你可以使用:-&gt; decltype(c.insert(std::forward&lt;T&gt;(t)), void()) 来减少代码膨胀。
  • @David:对,这更干净,让我编辑答案。谢谢!
  • 遗憾的是,尽管 g++ 编译了这个,VC2010 说:w32threads.h(45): error C2995: 'void insert_in_container(C &amp;,T &amp;&amp;)' : function template has already been defined
【解决方案2】:

insert(iterator, value_type) 重载并用end() 调用它怎么样?它在两者中都可用,应该做你想做的事!也适用于std::list

这里真的不需要类型分派。

【讨论】:

    【解决方案3】:

    由于 concepts-lite 应该有望在 C++14 中及时出现,我不妨向您展示届时将如何完成:

    template<typename J, typename CollectionT = std::vector<J>>
    class async_jobqueue
    {
      public:
    
        requires Associative_container<CollectionT>()
        void adding_function(const J& item) {
          // Uses insert
        }
    
        requires Sequence_container<CollectionT>()
        void adding_function(const J& item) {
          // Uses push_back
        }
    };
    

    当然,这还不可能(而且可能永远不可能)。不过,concepts-lite 的接受度相当不错。

    【讨论】:

    • 是的,看起来很干净。
    猜你喜欢
    • 2012-12-08
    • 2018-01-30
    • 1970-01-01
    • 2013-05-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-11
    • 2014-12-27
    相关资源
    最近更新 更多