简体   繁体   中英

Iterating over types in a variadic template

I have a member function that is templated with a variadic template. The member function wants to push to a container somewhere some information about the types in the variadic template, such as typeid(T) and sizeof(T) .

The member function should also take in a variable amount of parameters, with each parameter's type being what is specified in the variadic template. Any parameter not explicitly defined should default to a default construction of the type.

Basically this, but bar is somehow a variadic template and that code repeats for all of the types in the variadic template.

class foo {
private:
    std::unordered_map<std::type_index, std::size_t> typeinfo;

public:
    template<typename T>
    void bar(T myType = T()) {
        typeinfo.insert({ typeid(T), sizeof(T) });
        
        // do stuff with myType ...
    }
};

foo myfoo;
myfoo.bar<int, double>(); // myType<int> = 0, myType<double> = 0.0;
myfoo.bar<char, float>('a'); // myType<char> = 'a', myType<float> = 0.0f;
myfoo.bar<double, char>(32.4, 'b'); // myType<double> = 32.4, myType<char> = 'b'

Parameter pack cannot have default argument

so

template<typename... Ts>
void bar(Ts... = Ts()...) // ill-formed

What you can do is using 2 parameter-packs

class foo {
private:
    std::unordered_map<std::type_index, std::size_t> typeinfo;

public:
    // Us... is non deducible
    template<typename... Us, typename... Ts>
    void bar(Ts... /*args*/) {
        (typeinfo.insert({ typeid(Us), sizeof(Us) }), ...);
        // You might have to check that Ts... start Us...
        // use end of Us... for args...
    }
};

void test()
{
    foo myfoo;
    myfoo.bar<int, double>(); // Us=[int, double], Ts=[]
    myfoo.bar<char, float>('a'); // Us =[char, float], Ts = [char];
    myfoo.bar<double, char>(32.4, 'b'); // Us=[double, char], Ts=[double, int]
    myfoo.bar<char>(4.2f); // Us =[char], Ts = [float] !!!
}

Demo

To create a tuple with initial part from Us , and remaining defaulted, you might do

template <typename T, std::size_t I, typename Tuple>
T get_or_default(Tuple&& tuple)
{
    if constexpr (I < std::tuple_size_v<std::decay_t<Tuple>>) {
        return std::get<I>(std::forward<Tuple>(tuple));
    } else {
        return T{};
    }
}

template<typename... Ts, std::size_t... Is,  typename Tuple>
std::tuple<Ts...>
make_partial_tuple_impl(std::index_sequence<Is...>, Tuple&& tuple)
{
    return {get_or_default<Ts, Is>(std::forward<Tuple>(tuple))...};
}

template<typename... Ts, typename... Us>
std::tuple<Ts...> make_partial_tuple(Us&&... args)
{
    return make_partial_tuple_impl<Ts...>(
        std::make_index_sequence<sizeof...(Ts)>{},
        std::forward_as_tuple(std::forward<Us>(args)...));
}

Demo

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM