Шаблонная функция с переменным количеством аргументов

Хочу сделать впримерно вот такой код, но не пойму по каким ключевым словам искать примеры. Может кто сталкивался и сможет помочь

Есть некий конфиг class Config {...} config;, есть шаблонный класс, примерно такой:

template<class T>
class Ref {
    Ref(const Config&);
    ...
    T& get();
    const T& get();
};

т.е. как-то по Config создает внутри себя инстанс и возвращает ссылку.

Есть много классов вида:

class X {
    X();
    X(Ref<A> a, Ref<B>, ..., Ref<N>); // Много, но четко заданное количество аргументов
};

class Y {
    Y(Ref<C> a, Ref<B>);
};

class Z {
    Z(...);
    Z(Ref<C> a, Ref<B>, ... Ref<A>);
};

т.е. в классе есть разные конструкторы, но среди которых есть один с разным наборов аргуметнов типа Ref<>, у каждого класса может быть разное количество этих аргументов и они могут идти в разном порядке.

Хочется написать такую функцию билдер, что по заданному классу и конфигу возвращала инстанс на класс.

template<class T>
T makeInstance(const Config& config) {
   ...
   return T(????????);
}

Вызов:

auto obj = makeInstance<Onbject>(config);

Кто сталкивался с чем-то подобным?


Ответы (1 шт):

Автор решения: Mister_Jesus

Вот примерно так. Суть в том, что сначала мы получаем возможное количество Ref экземпляров, которых необходимо создать для конструктора (В функции count_of_arguments). С помощью AutoDeducer мы получаем внутренний тип T для Ref. Сейчас у меня функция count_of_arguments идет рекурсивно и в рантайме. Возможно с помощью decltype можно будет оптимизировать этот момент.

#include <type_traits>
#include <tuple>

struct Config
{};

template <typename T>
struct Ref
{
    Ref(Config a_Config)
    {}
};

struct AutoDeducer
{
    AutoDeducer(Config a_Config)
        : config { a_Config }
    {}

    template <typename T>
    operator Ref<T>() const
    {
        return Ref<T>{ config };
    }

    Config config;
};

template <typename T, typename ... Args>
constexpr decltype(auto) count_of_arguments() noexcept
{
    if constexpr (std::is_constructible_v<T, Args...>)
    {
        return std::make_index_sequence<sizeof...(Args)>{};
    }
    else
    {
        return count_of_arguments<T, AutoDeducer, Args...>();
    }
}

template <size_t T>
AutoDeducer CreateAutoDeducer(Config a_Config)
{
    return AutoDeducer{ a_Config };
}

template <typename T, size_t ... Indexes>
T make_object(Config a_Config, std::index_sequence<Indexes...>)
{
        return T{ CreateAutoDeducer<Indexes>(a_Config) ... };
}

template <typename T>
T make_object(Config a_Config)
{
    return make_object<T>(a_Config, count_of_arguments<T>());
}

struct Foo
{};

struct Tested1
{
    Tested1(Ref<Foo> a_Ref)
    {}
};

struct Tested2
{
    Tested2(Ref<Foo> a_Ref1, Ref<Foo> a_Ref2)
    {}
};

struct Tested3
{
    Tested3(Ref<Foo> a_Ref1, Ref<Foo> a_Ref2, Ref<Foo> a_Ref3)
    {}
};

int main()
{
    make_object<Tested1>(Config{});
    make_object<Tested2>(Config{});
    make_object<Tested3>(Config{});
}
→ Ссылка