Disclaimer: Вопрос баян и велосипед, но у меня свой интерес, заточенный под определённую специфику применения.
Задача: изобрести zero-cost метод вызвать функцию для каждого шаблонного параметра
Классика — рекурсия на шаблонах — не подходит, потому что генерит кучу лишних функций и за счёт раздувания кода её нельзя считать zero-cost. Плюс рекурсивные вызовы лишних функций.
Мой вариант тут (копия под катом), но он мне не нравится, т.к. работает только для функторов, и даже лямбду без бубна не подставишь. А хотелось бы иметь возможность использовать и для функции. Или хотя бы, чтобы были две функции — одна для функтора, другая для шаблонной функции
| | Копия кода |
| | #include <iostream>
#include <string>
#include <vector>
#include <tuple>
template <typename Arg> struct Print {
void operator()( Arg arg ) { std::cout << std::forward<Arg>(arg)<<std::endl; }
};
template <typename Arg> void Print2 ( Arg arg ) { std::cout << std::forward<Arg>(arg)<<std::endl; }
template < template <typename> class Callback, typename... Args> struct ForEachHelper {
void operator()( Args&& ... args) {
( ( Callback<decltype(std::forward<Args>(args))>()( std::forward<Args>(args) ) ),... );
}
};
template <template <typename> class Callback, typename... Args> void ForEach( Args&&... args ) {
ForEachHelper<Callback, Args...>()( std::forward<Args>(args)... );
}
int main()
{
ForEach<Print>( "aaa", 14, 0.34 );
return 0;
}
|
| | |
Можно ли сделать поэлегантней?
Только так, чтобы функция задавалась как параметр — шаблонный или обычный, не важно. Плюс, последовательность выполнения должна соответствовать последовательности следования аргументов.
Вот ещё несколько вариантов на стэковерфлоу
k13 предложил вариант, при котором можно заменить шаблонный функтор на обычный (но с шаблонным методом)
| | тык |
| | #include <iostream>
template< typename FN, typename... Args >
void ForEach( FN&& fn, Args... args )
{
(fn(std::forward<Args>(args)),...);
}
// шаблонный не функтор, а метод
struct Print {
template <typename Arg>
void operator()( Arg arg ) { std::cout << std::forward<Arg>(arg)<<std::endl; }
};
int main()
{
ForEach( [](auto x){ std::cout << x << std::endl; }, "aaa", 14, 0.34 );
ForEach( Print{}, "bbb", 13, 0.24 );
return 0;
}
|
| | |
#include <iostream>
template< typename FN, typename... Args >
void ForEach( FN&& fn, Args... args )
{
(fn(std::forward<Args>(args)),...);
}
// шаблонный не функтор, а метод
struct Print {
template <typename Arg>
void operator()( Arg arg ) { std::cout << std::forward<Arg>(arg)<<std::endl; }
};
int main()
{
ForEach( [](auto x){ std::cout << x << std::endl; }, "aaa", 14, 0.34 );
ForEach( Print{}, "bbb", 13, 0.24 );
return 0;
}