Есть число 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);
}
онлайн компилятор
Комментариев нет:
Отправить комментарий