Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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? */)
{
}
like image 207
Lorah Attkins Avatar asked May 25 '26 03:05

Lorah Attkins


2 Answers

#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

like image 122
Piotr Skotnicki Avatar answered May 26 '26 17:05

Piotr Skotnicki


You can create two parameter packs, one representing the types corresponding to function parameters and one representing "defaulted parameters."

template< typename ... aux, typename ... arg >
void fn( arg ... a ) {
    std::tuple< aux ... > more {}; // The tuple elements are value-initialized.
}

http://coliru.stacked-crooked.com/a/1baac4b877dce4eb

There is no way to explicitly mention the deduced template parameters for this function. Anything inside the angle braces of the call will go into aux, not arg.

Note, the initialization you get with {} is value-initialization, not default-initialization. Objects of fundamental type get zeroed, not left uninitialized.

like image 25
Potatoswatter Avatar answered May 26 '26 16:05

Potatoswatter



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!