【问题标题】:How do I write a make_vector similar to std::make_tuple?如何编写类似于 std::make_tuple 的 make_vector?
【发布时间】:2016-08-27 22:38:36
【问题描述】:

而不是像这样创建向量:

  std::vector<int>     v1{1,2,3};
  std::vector<double>  v2{1.1,2.2,3.3};
  std::vector<Object>  v3{Object{},Object{},Object{}};  

我想用一个通用函数来创建它们:

  auto v1 = make_vector(1,2,3);
  auto v2 = make_vector(1.1,2.2,3.3);
  auto v3 = make_vector(Object{},Object{},Object{}); 

类似于std::make_pairstd::make_tuple,这是我对向量的尝试:

#include <iostream>
#include <vector>
#include <utility>

template <typename... T>
auto make_vector(T&&... args)
{
    using first_type = typename std::tuple_element<0, std::tuple<T...>>::type;
    return std::vector<first_type>{std::forward<T>(args)...};
}

它可以编译,但是当我尝试使用它时:

auto vec = make_vector(1,2,3);  

m.cpp: In instantiation of ‘auto make_vector(T&& ...) [with T = {int, int, int}]’:
m.cpp:16:30:   required from here
m.cpp:8:78: error: invalid use of incomplete type ‘class std::tuple_element<0ul, std::tuple<int, int, int> >’
     using first_type = typename std::tuple_element<0, std::tuple<T...>>::type;
                                                                              ^
In file included from m.cpp:3:0:
/usr/include/c++/5/utility:85:11: note: declaration of ‘class std::tuple_element<0ul, std::tuple<int, int, int> >’
     class tuple_element;
           ^
m.cpp:9:60: error: invalid use of incomplete type ‘class std::tuple_element<0ul, std::tuple<int, int, int> >’
     return std::vector<first_type>{std::forward<T>(args)...};
                                                            ^
In file included from m.cpp:3:0:
/usr/include/c++/5/utility:85:11: note: declaration of ‘class std::tuple_element<0ul, std::tuple<int, int, int> >’
     class tuple_element;
           ^
m.cpp: In function ‘int main()’:
m.cpp:16:30: error: ‘void v1’ has incomplete type
   auto v1 = make_vector(1,2,3);  

我怎样才能制定一个通用的例程,
使用第一个参数的第一个类型来实例化向量?
如何将参数作为初始值设定项转发给向量?

【问题讨论】:

    标签: c++ templates c++11 variadic-templates perfect-forwarding


    【解决方案1】:

    就像你做的那样 - gcc 和 msvc 都用一个很小的 ​​#include &lt;tuple&gt; 编译你的函数。

    【讨论】:

      【解决方案2】:

      因为无论如何你都不能使用它来创建一个空向量,我们可以通过提供一个额外的模板参数来避免tuple 依赖:

      template <class T0, class... Ts>
      auto make_vector(T0&& first, Ts&&... args)
      {
          using first_type = std::decay_t<T0>;
          return std::vector<first_type>{
              std::forward<T0>(first),
              std::forward<Ts>(args)...
          };
      }
      

      如果first 作为左值传入,它还有一个额外的好处。

      【讨论】:

        【解决方案3】:

        让我们按照make_array 的引导,允许用户明确指定返回类型,或者使用由std::common_type 确定的返回类型。

        template<class T> struct identity { using type = T; };
        template<class D, class... Ts>
        struct ret : identity<D> {};
        template<class... Ts>
        struct ret<void, Ts...> : std::common_type<Ts...> {};
        template<class D, class... Ts>
        using ret_t = typename ret<D, Ts...>::type;
        
        template<class D = void, class... Ts>
        std::vector<ret_t<D, Ts...>> make_vector(Ts&&... args) {
            std::vector<ret_t<D, Ts...>>  ret;
            ret.reserve(sizeof...(args));
            using expander = int[];
            (void) expander{ ((void)ret.emplace_back(std::forward<Ts>(args)), 0)..., 0 };
            return ret;
        }
        

        完美转发的使用表明您要消除不必要的复制;这与使用需要每个元素的副本的 initalizer_list 构造函数不一致。因此,上面的代码 reserves 是适当的空间,然后 emplace_backs 使用通常的包扩展技巧将元素一一对应。

        如果您不想启用显式转换,则可以使用push_back 代替,但可能会导致类型不匹配。但是,在这种情况下,类型要么由用户显式指定,要么由common_type 通过隐式转换推导出来,所以emplace_back 可能就可以了。

        【讨论】:

        • 与其他make_vector 实现相比,这是更好的解决方案,因为它还支持仅移动类型。非常感谢!
        • 这不适用于像explicit FieldInfo(const std::string&amp; name, const char id, const int len, const bool is_required)这样的自定义类我这样称呼auto temp = make_vector&lt;FieldInfo&gt;(("Serial Num", 'S', 50, true), ("Customer", 'C', 18, true)
        猜你喜欢
        • 2017-04-16
        • 1970-01-01
        • 2010-12-09
        • 1970-01-01
        • 2020-12-08
        • 2011-12-13
        • 2012-06-05
        • 2020-03-11
        • 1970-01-01
        相关资源
        最近更新 更多