Страницы

Поиск по вопросам

среда, 27 ноября 2019 г.

Объявление функции n переменных


Есть число n. Как объявить функцию n переменных одного типа? Ситуация примерно такая:

using my_type = int;
constexpr size_t n = 4;

std::function(n))> my_func;

    


Ответы

Ответ 1



Первое, что пришло в голову: #include #include #include namespace details { template using get_type_t = T; template auto make_function_type_impl(::std::index_sequence) -> RetType (&)(get_type_t...); template using make_function_type = std::remove_reference_t(::std::make_index_sequence()))>; }//namespace details template using make_function_type_n = ::details::make_function_type; double foo(int x, int y) { return (double)x/y; } int main() { using my_type = int; constexpr size_t n = 2; std::function> my_func = foo; std::cout << my_func(10, 4); } http://rextester.com/CPMS17471 Работает это следующим образом. make_function_type_n Шаблонный using разворачивается в: ::details::make_function_type В свою очередь этот шаблонный using разворачивается в std::remove_reference_t(::std::make_index_sequence<2>()))>; ::std::make_index_sequence<2>() создаст объект типа std::index_sequence<0, 1>// где 0 и 1 - это индексы до 2. т.е. у нас в decltype попадает выражение make_function_type_impl(::std::index_sequence<0, 1>) Следовательно, получаем следующее: make_function_type_impl(::std::index_sequence<0, 1>) -> double (&)(get_type_t, get_type_t) Таким образом decltype даст ссылку на функцию типа double(int, int), а ссылка удаляется с помощью std::remove_reference_t. Пока писал, возникла идея повторить не один параметр, а несколько. Для начала нужна будет структура, которая будет хранить нужный тип функции и наращивать его параметры. namespace details { template struct func_n_t { using type = RetType(Params...);//Тип функции //Этот шаблонный using будет хранить тип func_n_t с параметрами, добавленными к текущим template using add = func_n_t; }; Всё что остается сделать - создать func_n_t с повторенными N раз параметрами. template<::std::size_t N, typename Func, typename ... Args> struct function_n_t_impl { //Применяем рекурсию шаблонов. //На каждом шаге к инстансу шаблона func_n_t прибавляются аргументы Args //При этом N уменьшается на 1 using type = typename function_n_t_impl, Args...>::type; }; //Частичная специализация, которая остановит рекурсию template struct function_n_t_impl<0, Func, Args...> { //Просто берем от типа Func тип нужной нам функции using type = typename Func::type; }; }//namespace details //Псевдоним, который запускает формирование нужного типа, начиная с func_n_t (т.е. с type = RetType()) template<::std::size_t N, typename RetType, typename ... ArgsType> using make_function_t = typename ::details::function_n_t_impl, ArgsType...>::type; Использование: //Указатель на функцию, возвращающую double и принимающую два параметра типа int make_function_t<2, double, int>* my_foo = foo; Полный код: #include #include namespace details { template struct func_n_t { using type = RetType(Params...);//Тип функции //Этот шаблонный using будет хранить тип func_n_t с параметрами, добавленными к текущим template using add = func_n_t; }; template<::std::size_t N, typename Func, typename ... Args> struct function_n_t_impl { //Применяем рекурсию шаблонов. //На каждом шаге к инстансу шаблона func_n_t прибавляются аргументы Args //При этом N уменьшается на 1 using type = typename function_n_t_impl, Args...>::type; }; //Частичная специализация, которая остановит рекурсию template struct function_n_t_impl<0, Func, Args...> { //Просто берем от типа Func тип нужной нам функции using type = typename Func::type; }; }//namespace details //Псевдоним, который запускает формирование нужного типа, начиная с func_n_t (т.е. с type = RetType()) template<::std::size_t N, typename RetType, typename ... ArgsType> using make_function_t = typename ::details::function_n_t_impl, ArgsType...>::type; //Функции для теста double foo(int x, int y) { std::cout << "foo(" << x << ", " << y << ")\n"; return (double)x/y; } double bar(int x1, double y1, int x2, double y2) { std::cout << "bar(" << x1 << ", " << y1 << ", " << x2 << ", " << y2 << ")\n"; return x1/y1 + x2/y2; } void zoo() { std::cout << "zoo\n"; } int main() { //Функция, возвращающая double и принимающая два параметра типа int make_function_t<2, double, int>* my_foo = foo; //Функция, возвращающая double и принимающая четыре параметра: int double, int double //Набор параметров int, double повторяется два раза. std::function> my_bar = bar; //Функции, возвращающие void и не принимающие параметров std::function> my_zoo1 = zoo;//10 пустых наборов std::function> my_zoo2 = zoo;// наборов int, size_t, void my_foo(10, 4); my_bar(10, 4.6, 15, 5.3); my_zoo1(); my_zoo2(); } http://rextester.com/HWBJA2947

Ответ 2



Можно записать несколько короче, не используя стандартную библиотеку и оставаяс в рамках C++11: template class t_n_args_fun_impl final { public: using t_fun = typename t_n_args_fun_impl::t_fun; }; template class t_n_args_fun_impl final { public: using t_fun = TResult (TArgs...); }; template using t_n_args_fun = typename t_n_args_fun_impl::t_fun; #include #include int main() { static_assert ( ::std::is_same < ::std::function> , ::std::function >::value , "" ); static_assert ( ::std::is_same < ::std::function> , ::std::function >::value , "" ); return(0); } онлайн компилятор

Комментариев нет:

Отправить комментарий