Home > Back-end >  C 20 : Parameter pack partial expansion
C 20 : Parameter pack partial expansion

Time:08-21

I need a way to partially expand a parameter pack. The size of the subset has to be determined by another variadic parameter. It will be more clear what I mean with sample code.


struct EntityA {
    EntityA(int, char, unsigned) {}
    EntityA(int, char, unsigned*) {}
    EntityA(int, char*, unsigned*) {}
    EntityA(int*, char*, unsigned*) {}
}
// various types of entities
// ...

// Service provides Args. 
template <typename ... Args>
struct Service {
    // returns provided Args
    template <typename T>
    T get() { return T{}; }
};

// this function should call appropriate overload of E by looking at sizeof...(pArgs)
template <typename E, typename ... SArgs>
E
construct(Service<SArgs ...>& service, auto&& ... pArgs) {
    // somehow i need to expand and get first half from service and get others from parameters
    return E{service.get<SArgs> ..., std::forward<decltype(pArgs)>(pArgs) ...};
}


int main() {
    Service<int, char, unsigned> service;
    construct<EntityA>(service);
    construct<EntityA>(service, (unsigned*)nullptr);
    construct<EntityA>(service, (char*)nullptr, (unsigned*)nullptr);
    construct<EntityA>(service, (int*)nullptr, (char*)nullptr, (unsigned*)nullptr);

    return 0;
}

Some objects(template parameter E) need to be constructed with parameters partially from service and partially from client code. Is there a way to implement this?

CodePudding user response:

you can use std::index_sequence for that

template <typename E, typename ... SArgs, typename ... PArgs> 
E construct(Service<SArgs...>& service, PArgs&& ... pargs) {
    constexpr auto size = sizeof...(PArgs);
    constexpr auto missing_size = 3 - size; // note: you need to somehow know the parameter count
    using default_types = std::tuple<SArgs...>;

    return [&]<std::size_t ...I>(std::index_sequence<I...>){
            return E{
                service.template get<std::tuple_element_t<I,default_types>>()...,
                std::forward<PArgs>(pargs)...
            };
        }(std::make_index_sequence<missing_size>());
}

https://godbolt.org/z/PY4hYrqK7

  • Related