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
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