Есть число n
. Как объявить функцию n
переменных одного типа? Ситуация примерно такая:
using my_type = int;
constexpr size_t n = 4;
std::function<void(give_me_n_types<my_type>(n))> my_func;
Первое, что пришло в голову:
#include <iostream>
#include <utility>
#include <functional>
namespace details
{
template<typename T, ::std::size_t = 0>
using get_type_t = T;
template<typename RetType, typename ArgsType, ::std::size_t ... I>
auto make_function_type_impl(::std::index_sequence<I...>) -> RetType (&)(get_type_t<ArgsType, I>...);
template<typename RetType, typename ArgsType, ::std::size_t N>
using make_function_type = std::remove_reference_t<decltype(make_function_type_impl<RetType, ArgsType>(::std::make_index_sequence<N>()))>;
}//namespace details
template<typename RetType, typename ArgsType, ::std::size_t N>
using make_function_type_n = ::details::make_function_type<RetType, ArgsType, N>;
double foo(int x, int y)
{
return (double)x/y;
}
int main()
{
using my_type = int;
constexpr size_t n = 2;
std::function<make_function_type_n<double, my_type, n>> my_func = foo;
std::cout << my_func(10, 4);
}
http://rextester.com/CPMS17471
Работает это следующим образом.
make_function_type_n<double, int, 2>
Шаблонный using разворачивается в:
::details::make_function_type<double, int, 2>
В свою очередь этот шаблонный using разворачивается в
std::remove_reference_t<decltype(make_function_type_impl<double, int>(::std::make_index_sequence<2>()))>;
::std::make_index_sequence<2>()
создаст объект типа
std::index_sequence<0, 1>// где 0 и 1 - это индексы до 2.
т.е. у нас в decltype попадает выражение
make_function_type_impl<double, int>(::std::index_sequence<0, 1>)
Следовательно, получаем следующее:
make_function_type_impl(::std::index_sequence<0, 1>) -> double (&)(get_type_t<int, 0>, get_type_t<int, 1>)
Таким образом decltype даст ссылку на функцию типа double(int, int)
, а ссылка удаляется с помощью std::remove_reference_t.
Пока писал, возникла идея повторить не один параметр, а несколько.
Для начала нужна будет структура, которая будет хранить нужный тип функции и наращивать его параметры.
namespace details
{
template<typename RetType, typename ... Params>
struct func_n_t {
using type = RetType(Params...);//Тип функции
//Этот шаблонный using будет хранить тип func_n_t с параметрами, добавленными к текущим
template<typename ... Args>
using add = func_n_t<RetType, Params..., Args...>;
};
Всё что остается сделать - создать 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<N - 1, typename Func::template add<Args...>, Args...>::type;
};
//Частичная специализация, которая остановит рекурсию
template<typename Func, typename ... Args>
struct function_n_t_impl<0, Func, Args...>
{
//Просто берем от типа Func тип нужной нам функции
using type = typename Func::type;
};
}//namespace details
//Псевдоним, который запускает формирование нужного типа, начиная с func_n_t<RetType> (т.е. с type = RetType())
template<::std::size_t N, typename RetType, typename ... ArgsType>
using make_function_t = typename ::details::function_n_t_impl<N, details::func_n_t<RetType>, ArgsType...>::type;
Использование:
//Указатель на функцию, возвращающую double и принимающую два параметра типа int
make_function_t<2, double, int>* my_foo = foo;
Полный код:
#include <iostream>
#include <functional>
namespace details
{
template<typename RetType, typename ... Params>
struct func_n_t {
using type = RetType(Params...);//Тип функции
//Этот шаблонный using будет хранить тип func_n_t с параметрами, добавленными к текущим
template<typename ... Args>
using add = func_n_t<RetType, Params..., Args...>;
};
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<N - 1, typename Func::template add<Args...>, Args...>::type;
};
//Частичная специализация, которая остановит рекурсию
template<typename Func, typename ... Args>
struct function_n_t_impl<0, Func, Args...>
{
//Просто берем от типа Func тип нужной нам функции
using type = typename Func::type;
};
}//namespace details
//Псевдоним, который запускает формирование нужного типа, начиная с func_n_t<RetType> (т.е. с type = RetType())
template<::std::size_t N, typename RetType, typename ... ArgsType>
using make_function_t = typename ::details::function_n_t_impl<N, details::func_n_t<RetType>, 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<make_function_t<2, double, int, double>> my_bar = bar;
//Функции, возвращающие void и не принимающие параметров
std::function<make_function_t<10, void>> my_zoo1 = zoo;//10 пустых наборов
std::function<make_function_t<0, void, int, size_t, void>> my_zoo2 = zoo;//0 наборов int, size_t, void
my_foo(10, 4);
my_bar(10, 4.6, 15, 5.3);
my_zoo1();
my_zoo2();
}
http://rextester.com/HWBJA2947
Можно записать несколько короче, не используя стандартную библиотеку и оставаясь в рамках C++11:
template<typename TResult, typename TArg, int remaining_args_count, typename... TArgs> class
t_n_args_fun_impl final
{
public: using t_fun = typename t_n_args_fun_impl<TResult, TArg, remaining_args_count - 1, TArgs..., TArg>::t_fun;
};
template<typename TResult, typename TArg, typename... TArgs> class
t_n_args_fun_impl<TResult, TArg, 0, TArgs...> final
{
public: using t_fun = TResult (TArgs...);
};
template<typename TResult, typename TArg, int args_count> using
t_n_args_fun = typename t_n_args_fun_impl<TResult, TArg, args_count>::t_fun;
#include <functional>
#include <type_traits>
int main()
{
static_assert
(
::std::is_same
<
::std::function<t_n_args_fun<void, double, 5>>
, ::std::function<void (double, double, double, double, double)>
>::value
, ""
);
static_assert
(
::std::is_same
<
::std::function<t_n_args_fun<void, void, 0>>
, ::std::function<void (void)>
>::value
, ""
);
return(0);
}
онлайн компилятор
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
Ребят, помогите найти код алгоритма COS(дискретное логарифмирование), очень надо
Ребят, помогите, пожалуйста найти код алгоритм Адлемана, очень надо
Как написать свою UDF для mysql на java? (для желающих больших вопросов добавлено) - нужны ссылки как надо написать на java, а не на С, что вызывать, как...
Я создаю SSLSocket для шифрованного подключения к серверамНа серверах настроено шифрование TLSv1