【问题标题】:tuple vector and initializer_list元组向量和 initializer_list
【发布时间】:2012-09-08 07:56:36
【问题描述】:

我尝试用gcc4.7编译下面的sn-ps

vector<pair<int,char> > vp = {{1,'a'},{2,'b'}};
//For pair vector, it works like a charm.

vector<tuple<int,double,char> > vt = {{1,0.1,'a'},{2,4.2,'b'}};

但是,对于元组的向量,编译器会抱怨:

错误:从初始化列表转换为“std::tuple”将使用显式构造函数“constexpr std::tuple::tuple(_UElements&& ...) [with _UElements = {int, double, char}; =无效; _Elements = {int, double, char}]'

编译器溢出的错误信息对我来说完全是胡言乱语,我不知道元组的构造函数是如何实现的,但我知道它们完全可以使用统一初始化(例如:tuple&lt;int,float,char&gt;{1,2.2,'X'}),因此,不知道我遇到的问题只是编译器的一个TODO还是C++11标准定义的问题。

【问题讨论】:

    标签: c++ c++11 tuples initializer-list


    【解决方案1】:

    相关的std::tuple 构造函数是explicit。这意味着您想要做的事情是不可能的,因为您要使用的语法是根据复制初始化定义的(禁止调用explicit 构造函数)。相比之下,std::tuple&lt;int, float, char&gt; { 1, 2.2, 'X' } 使用直接初始化。 std::pair 确实只有非explicit 构造函数。

    使用直接初始化或标准元组工厂函数之一(例如std::make_tuple)。

    【讨论】:

    • 它已在 C++17 中进行了条件显式(在本例中为非显式)。
    【解决方案2】:

    这实际上是可行的,具有 c++11 的特性。

    是的,initializer_list 希望它的所有元素都属于同一类型。诀窍是我们可以创建一个包装类,它可以是 static_cast 到我们想要的所有类型。这很容易实现:

     template <typename... tlist>
     class MultiTypeWrapper {
     };
    
     template <typename H>
     class MultiTypeWrapper<H> {
     public:
       MultiTypeWrapper() {}
    
       MultiTypeWrapper(const H &value) : value_(value) {}
    
       operator H () const {
         return value_;
       }
     private:
       H value_;
     };
    
     template <typename H, typename... T>
     class MultiTypeWrapper<H, T...> 
       : public MultiTypeWrapper<T...> {
    
     public:
       MultiTypeWrapper() {}
    
       MultiTypeWrapper(const H &value) : value_(value) {}
    
       // If the current constructor does not match the type, pass to its ancestor.
       template <typename C>
       MultiTypeWrapper(const C &value) : MultiTypeWrapper<T...>(value) {}
    
       operator H () const {
         return value_;
       }
     private:
       H value_;
     };
    

    使用隐式转换构造函数,我们可以将 {1,2.5,'c',4} 之类的内容传递给 MultiTypeWrapper 类型的 initializer_list(或向量,它隐式转换 initializer_list)。这意味着我们不能编写像 below 这样的函数来接受这样的 intializer_list 作为参数:

    template <typename... T>
    std::tuple<T...> create_tuple(std::vector<unit_test::MultiTypeWrapper<T...> > init) {
      ....
    }
    

    我们使用另一个技巧将向量中的每个值转换为其原始类型(请注意,我们在MultiTypeWrapper 的定义中提供了隐式转换)并将其分配给元组中的相应槽。这就像对模板参数的递归:

    template <int ind, typename... T>
    class helper {
    public:
      static void set_tuple(std::tuple<T...> &t, const std::vector<MultiTypeWrapper<T...> >& v) {
        std::get<ind>(t) = static_cast<typename std::tuple_element<ind,std::tuple<T...> >::type>(v[ind]);
        helper<(ind-1),T...>::set_tuple(t,v);
      }
    };
    
    
    
    template <typename... T>
    class helper<0, T...> {
    public:
      static void set_tuple(std::tuple<T...> &t, const std::vector<MultiTypeWrapper<T...> >& v) {
        std::get<0>(t) = static_cast<typename std::tuple_element<0,std::tuple<T...> >::type>(v[0]);
      }
    };
    
    
    
    template <typename... T>
    std::tuple<T...> create_tuple(std::vector<unit_test::MultiTypeWrapper<T...> > init) {
      std::tuple<T...> res;
      helper<sizeof...(T)-1, T...>::set_tuple(res, init);
      return res;
    }
    

    请注意,我们必须为set_tuple 创建帮助类,因为 c++ 不支持函数特化。现在如果我们要测试代码:

    auto t = create_tuple<int,double,std::string>({1,2.5,std::string("ABC")});
    printf("%d %.2lf %s\n", std::get<0>(t), std::get<1>(t), std::get<2>(t).c_str());
    

    输出将是:

    1 2.50 ABC
    

    这是在我的桌面上使用 clang 3.2 测试的

    希望我的意见有所帮助:)

    【讨论】:

    • 酷,但我不认为 OP 只是为了能够将元组推入向量中而编写一个包装类。至少,我不会那样做。
    【解决方案3】:

    很烦不是吗?我之前也使用过对 - 在类似的场景中,很惊讶元组不支持这一点,因为 {} 初始化语法节省了很多混乱。您可以使用 ma​​ke_tuple 在容器中手动插入元素,因此:

    vt.push_back(make_tuple(2,4.2,'b'));
    

    应该有效

    【讨论】:

      【解决方案4】:

      你不能仅仅使用 accolades 来初始化元组,你必须使用关键字 tuple 来代替

      vector<tuple<int, int>> my_vec{
          tuple<int, int> { 1, 15 },
          tuple<int, int> { 2, 100 }
      };
      

      C++ 11

      【讨论】:

        猜你喜欢
        • 2021-01-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-08-15
        • 1970-01-01
        • 2021-03-11
        • 1970-01-01
        • 2018-01-17
        相关资源
        最近更新 更多