Search code examples
c++c++11templatesvariadic-templates

Default initialized (with value initialization) parameter pack


Can I default initialize a parameter pack to the respective value initialization of each type ?

To elaborate a bit more, take the example of a simple function template

template<typename T>
void f(T arg = T())
{ 
  // eg for T=int, arg is 0 (value initialization) when default initialized
}

Would it be possible to express its variadic counterpart, ie

template<typename... Args>
void F(Args... args /* how can I value initialize the parameter pack? */)
{
}

Solution

  • #include <iostream>
    #include <utility>
    #include <tuple>
    #include <cstddef>
    #include <type_traits>
    
    template <typename... Args>
    void F(Args... args)
    {
        // target function, arbitrary body
        using expander = int[];
        (void)expander{ 0, (void(std::cout << args << " "), 0)... };
        std::cout << std::endl;
    }
    
    template <typename... Args, typename... Params, std::size_t... Is>
    void F(std::index_sequence<Is...>, Params&&... params)
    {
        F<Args...>(std::forward<Params>(params)...
                 , std::decay_t<typename std::tuple_element<sizeof...(Params) + Is, std::tuple<Args...>>::type>{}...);
    }
    
    template <typename... Args, typename... Params>
    auto F(Params&&... params)
        -> std::enable_if_t<(sizeof...(Args) > sizeof...(Params))>
    {
        F<Args...>(std::make_index_sequence<sizeof...(Args) - sizeof...(Params)>{}
                 , std::forward<Params>(params)...);
    }
    

    Tests:

    #include <string>
    
    int main()
    {
        // F(int, char, float = float{}, double = double{})
        F<int, char, float, double>(1, 'c');
    
        // F(int = int{}, char = char{}, float = float{}, double = double{})     
        F<int, char, float, double>();
    
        // F(const std::string&, const std::string& = std::string{})
        F<const std::string&, const std::string&>("foo");
    
        // F(int, int, int)
        F(1, 2, 3);
    }
    

    Output:

    1 'c' 0 0 
    0 '\0' 0 0
    "foo" ""
    1 2 3
    

    DEMO