Шаблонная функция с переменным количеством аргументов
Хочу сделать впримерно вот такой код, но не пойму по каким ключевым словам искать примеры. Может кто сталкивался и сможет помочь
Есть некий конфиг 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 шт):
Вот примерно так. Суть в том, что сначала мы получаем возможное количество 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{});
}