For constructors, how do I choose between variadic-templates vs std::initializer_list?

后端 未结 3 1173
南笙
南笙 2021-02-14 01:13

In the current state of c++11 (say gcc 4.7.2), how should I choose between using a variadic-template or a std::initializer_list when I need a constructor t

3条回答
  •  挽巷
    挽巷 (楼主)
    2021-02-14 01:43

    I recommend always chosing variadic templates and avoid std::initializer_list whenever possible.

    This is how I would have implemented std::vector with C++11:

    #include 
    #include 
    
    struct exp_sequence {
      template 
      exp_sequence(T&&...) {}
    };
    
    struct from_arglist_t {} from_arglist;
    
    template 
    class my_vector {
      std::vector data;
    
    public:
      my_vector(int n, T const& e) : data(n, e) {}
    
      template 
      my_vector(from_arglist_t, Args&&... args) {
        data.reserve(sizeof...(Args));
        exp_sequence{(data.push_back(std::forward(args)),1)...};
      }
    
      std::size_t size() { return data.size(); }
    };
    
    int main()
    {
      std::vector v1{13, 13}; std::cout << v1.size() << '\n'; // 2
      std::vector v2(13, 13); std::cout << v2.size() << '\n'; // 13
    
      my_vector v3{13, 13}; std::cout << v3.size() << '\n'; // 13
      my_vector v4(13, 13); std::cout << v4.size() << '\n'; // 13
      my_vector v5(from_arglist, 13, 13); std::cout << v5.size() << '\n'; // 2
      my_vector v6{from_arglist, 13, 13}; std::cout << v6.size() << '\n'; // 2
    }
    

    The reason is as showed in main, using initializer_list in generic code can lead to different behaviour depending on which type of parentheses was chosen. There is also the possibility to silently change code by adding such an constructor.

    Another reason are move-only types:

    //std::vector m1{move_only{}}; // won't compile
    my_vector m2{from_arglist, move_only{}}; // works fine
    

提交回复
热议问题