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

c++, c++11, initializer-list, templates, variadic-templates

Solution

A variadic template allows you providing arguments of different types, while an `std::initializer_list` is templated with the type of the argument. This means the type of all the elements in the list must be the same (or convertible to the underlying type, but no narrowing conversions are allowed). Depending on whether or not this is desirable for you, you may choose one or the other.

Also, a variadic template is usually the default choice if you need perfect forwarding, in that the syntactic form `T&&` can bind to both lvalue references and rvalue references, while a similar type deduction cannot be performed for `initializer_list`:

struct A
{
    // Deduces T& for lvalue references, T for rvalue references, and binds to both
    template<typename... Ts>
    A(Ts&&...) { }

    // This is an rvalue reference to an initializer_list. The above type deduction
    // does not apply here
    template<typename T>
    A(initializer_list<T>&&) { }
};

Also notice, that a constructor accepting an `initializer_list` will be invoked by default when you use uniform initialization syntax (i.e. curly braces), even though another viable constructor exists. This may or may not be something you wish to have:

struct A
{
    A(int i) { }
};

struct B
{
    B(int) { }
    B(std::initializer_list<A>) { }
};

int main()
{
    B b {1}; // Will invoke the constructor accepting initializer_list
}

Problem

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 that can take variable arguments?

Original source