Я тестировал вариационные функции, надеясь, что я могу использовать его для решения проблемы, в которой мне нужно создать объект, содержащий произвольное количество аргументов. Он действительно работает отлично, но аргументы, переданные функции createObject, должны быть динамическими. В приведенном ниже примере только два аргумента передаются конструктору, но в конечной программе число и порядок, в которых передаются аргументы, должны быть произвольными (аргументы всегда имеют тип Param хотя).
Кажется, я не могу найти способ сделать это. Любая помощь, идеи и т.д. Были бы весьма признательны.
PS: Я нашел пару подобных вопросов в Stackoverflow, но они старые и не дают никакого приемлемого ответа.
struct Vec3f { float x, y, z; };
struct Vec2f { float x, y; };
template<class T>
struct Param
{
static const std::size_t size = sizeof(T);
Param(const std::string &n) : name(n) {}
std::string name;
};
typedef Param<Vec3f> ParamFloat3;
typedef Param<Vec2f> ParamFloat2;
void parseParameters(std::size_t &stride) {}
template<class T, typename ... Types>
void parseParameters(std::size_t &stride, const Param<T> &first, Types ... args)
{
stride += first.size;
parseParameters(stride, args ...);
}
template<class T, typename ... Types>
void createObject(const Param<T> &first, Types ... args)
{
std::size_t stride = 0;
parseParameters(stride, first, args...);
}
int main(int argc, char **argv)
{
ParamFloat3 test1("T1");
ParamFloat2 test2("T2");
createObject(test1, test2); // would like to make this dynamic
return 0;
}
Все виды программирования шаблонов (включая вариационные шаблоны) разрешаются во время компиляции. Вам нужно будет передать контейнер (например, std::vector
) в ваши функции.
Edit: Если вам нужно передавать параметры разных типов (Param<Vec3f>
и Param<Vec2f>
на самом деле Param<Vec2f>
отличаются друг от друга, несмотря на то, что они поступают из одного и того же шаблона), вам нужно будет полагаться на полиморфизм. Дайте всем параметрам один и тот же базовый класс и используйте виртуальные функции или dynamic_cast
для восстановления правильного поведения.
Самый безопасный способ добиться этого (и избегать обрезки объектов) - использовать std::vector<std::unique_ptr<Param>>
где Param - ваш базовый класс.
dynamic_cast
в лучшем случае.
Вместо того, чтобы проверять первый аргумент как Param<T>
, вы можете вывести весь аргумент:
template<class Head, class... Tail>
void parseParameters(std::size_t& stride, Head&& head, Tail&&... tail)
{
stride += head.size;
parseParameters(stride, std::forward<Tail>(tail)...);
}
template<class... Args>
void createObject(Args&&... args)
{
std::size_t stride = 0;
parseParameters(stride, std::forward<Args>(args)...);
}
Вы также можете отключить различные перегрузки и включить других, если вы намерены использовать разные функции в зависимости от типа.
createObject
, должны быть динамическими"? Что значит «динамический» здесь?