Search code examples
c++templatesvariadic-functionsinitializer-list

How can I pass std::initializer_list in a variable number of arguments?


I would like to pass a std::initializer_list inside a variable number of arguments for a function that print each argument.

func( 1, 2.5, 'a', "Hello", {10, 20, 30, 40 } );

Expecting this output:

1
2.5
a
Hello
{ 10, 20, 30, 40, }

I tried to implement it following this answer from another question.

#include <iostream>
#include <initializer_list>

template <typename T>
void func_(std::initializer_list<T> list ) 
{
    std::cout << "{ ";
    for( const T& elem : list )
    {
       std::cout << elem << ", ";
    }
    std::cout << "}" << std::endl;
}

template <typename T>
void func_(T t) 
{
    std::cout << t << std::endl;
}

void func(){}

template<typename T, typename... Args>
void func(T t, Args... args) // recursive variadic function
{
    func_(t);
    func(args...) ;
}

int main()
{
    func( 1,2.5,'a', "Hello", {10, 20, 30, 40 });
}

Another way that I tried to implemented func

template <typename T, typename S>
void func(T t) 
{
    if constexpr (std::is_same<T, std::initializer_list<S>>::value)
    {
        std::cout << "{ ";
        for( const S& elem : t )
        {
            std::cout << elem << ", ";
        }
        std::cout << "}" << std::endl;
    }
    else
        std::cout << t << std::endl;
}

template<typename T, typename... Args>
void func(T t, Args... args) // recursive variadic function
{
    func(t);
    func(args...);
}

None of them worked


Solution

  • The problem is that a braced init list does not have a type. So we have to explicitly specify the type specifier.

    The simplest way I can think of is to create a class with an std::initializer_list ctor and overloaded operator<< and then use it as shown below.

    template<typename T>
    struct V
    {
        V(std::initializer_list<T> v): m_t(v){}
        friend std::ostream& operator<<(std::ostream& os, const V& v)
        {
            std::cout << "{ ";
            for(const auto i: v.m_t)  
            {
                 std::cout << i << " "; 
            }
            std::cout << "}";
            return os;
        }
        std::initializer_list<T> m_t;
    };
    func_( 1,2.5,'a', "Hello", V{10, 20, 30, 40 }); //works now
    

    Working demo

    The output of the above program is(the same as your expected output):

    1
    2.5
    a
    Hello
    { 10 20 30 40 }
    

    It can be further customized as per your needs.