tuple vector and initializer_list

前端 未结 3 513
太阳男子
太阳男子 2021-01-03 18:31

I tried to compile the following snippets with gcc4.7

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


        
3条回答
  •  时光说笑
    2021-01-03 19:22

    This is actually doable, with c++11 features.

    Yes the initializer_list wants all its element to be of the same type. The trick is that we can create a wrapper class that can be static_cast to all the types we want. This is easy to achieve:

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

    With the implicit conversion constructors, we can pass something like {1,2.5,'c',4} to an initializer_list (or vector, which implicitly converts the initializer_list) of type MultiTypeWrapper. This means that we can not write a function like below to accept such intializer_list as argument:

    template 
    std::tuple create_tuple(std::vector > init) {
      ....
    }
    

    We use another trick to cast each value in the vector to its original type (note that we provide implicit conversion in the definition of MultiTypeWrapper) and assign it to the corresponding slot in a tuple. It's like a recursion on template arguments:

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

    Note that we have to create the helper class for set_tuple since c++ does not support function specialization. Now if we want to test the code:

    auto t = create_tuple({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());
    

    The output would be:

    1 2.50 ABC
    

    This is tested on my desktop with clang 3.2

    Hope my input helps :)

提交回复
热议问题