Когда-то давно по материалам из Интернета сделал собственный аналог функции std::apply из C++17, но для C++11. Для тех счастливчиков, которые никогда не сталкивались с std::apply или его аналогами скажу, что std::apply позволяет вызвать нужную вам функцию, передав в нее содержимое имеющегося у вас std::tuple. Т.е. фокус в том, чтобы распаковать содержимое std::tuple в набор аргументов вызываемой функции.
В C++11 для такого трюка не было вообще никаких готовых инструментов. В C++14 уже появился std::index_sequence, на базе которого основная магия и происходит. Ну а в C++17 уже есть std::apply. Но мне в свое время нужно было именно для C++11, поэтому и появилась реализация call_by_tuple. Появилась и так и валяется у меня на винте. Время от времени ее приходится искать. И, для того, чтобы искать было проще, решил ее код опубликовать в склерозникблоге.
Поиграться в он-лайн компиляторе с моим вариантом call_by_tuple можно на wandbox-е. Исходный текст этого же примера с реализацией call_by_tuple под катом.
#include <iostream> #include <tuple> #include <type_traits> template< size_t... > struct sequence {}; template< size_t I, size_t... S > struct generate_sequence : generate_sequence< I - 1, I - 1, S... > {}; template< size_t... S > struct generate_sequence< 0, S... > { using type = sequence< S... >; }; template< size_t... S, typename C, typename... A > auto call_by_tuple_impl( sequence< S... >, C && c, const std::tuple< A... > & args ) -> typename std::result_of< C(A...) >::type { return c( std::get<S>( args )... ); } template< size_t... S, typename C, typename... A > auto call_by_tuple_impl( sequence< S... >, C && c, std::tuple< A... > & args ) -> typename std::result_of< C(A...) >::type { return c( std::get<S>( args )... ); } template< typename C, typename... A > auto call_by_tuple( C && c, const std::tuple<A...> & args ) -> typename std::result_of< C(A...) >::type { return call_by_tuple_impl( typename generate_sequence< sizeof...(A) >::type(), std::forward< C >(c), args ); } template< typename C, typename... A > auto call_by_tuple( C && c, std::tuple<A...> & args ) -> typename std::result_of< C(A...) >::type { return call_by_tuple_impl( typename generate_sequence< sizeof...(A) >::type(), std::forward< C >(c), args ); } int one( int a ) { std::cout << "one: " << a << std::endl; return a; } int two( int a, int b ) { std::cout << "two: " << a << ", " << b << std::endl; return a+b; } void three( std::string a, std::string b ) { std::cout << "three: " << a << ", " << b << std::endl; a = "-" + a + "-"; b = "(" + b + ")"; } int main() { auto t1 = std::make_tuple( 1 ); auto t2 = std::make_tuple( 1, 2 ); call_by_tuple( one, std::make_tuple( 1 ) ); call_by_tuple( one, t1 ); call_by_tuple( two, std::make_tuple( 1, 2 ) ); call_by_tuple( two, t2 ); auto t3 = std::make_tuple< std::string, std::string >( "a", "b" ); call_by_tuple( three, t3 ); } |
Комментариев нет:
Отправить комментарий