boost::phoenix
boost::phoenix in OnePage
boost::phoenix Quick Look in OnePage
boost::phoenix Tutorial in OnePage
The argument placeholder acts as an imaginary data-bin where a function argument will be placed.
#include <boost/phoenix.hpp> #include <algorithm> #include <vector> #include <iostream> #include <numeric> namespace phoe = boost::phoenix; using phoe::arg_names::arg1; using phoe::arg_names::arg10; // arg1, arg2, ..., arg10 int main() { std::vector<int> vector(10); std::iota(vector.begin(), vector.end(), 1); std::ranges::for_each(vector, std::cout << arg1 << ' '); std::cout << '\n'; }
Values are immutable constants. Attempting to modify a value will result in a compile time error. References are actors. Hence, references can be evaluated.
#include <boost/phoenix.hpp> #include <iostream> namespace phoe = boost::phoenix; using phoe::arg_names::arg1; int main() { int x = 3; // values std::cout << phoe::val(12)() << ' ' << phoe::val(x)() << '\n'; // 12 3 // references std::cout << phoe::ref(x)++() << ' ' << phoe::ref(x)() << '\n'; // 3 4 (phoe::ref(x)=9)(); // ok std::cout << x << '\n'; // 9 //(phoe::val(x)=8)(); // error }
The function class template provides a mechanism for implementing lazily evaluated functions. Syntactically, a lazy function looks like an ordinary c++ function. The function call looks familiar and feels the same as ordinary c++ functions. However, unlike ordinary functions, the actual function execution is deferred.
#include <boost/phoenix.hpp> #include <utxcpp/core.hpp> #include <complex> // std::sqrt namespace phoe = boost::phoenix; using phoe::arg_names::arg1; using phoe::arg_names::arg2; class sqrt_function { public: template <typename signature> class result; template <typename this_type, typename arg_type> class result<this_type(const arg_type &)> { public: using type = utx::fmax; }; template <typename arg_type> using result_t = typename result<sqrt_function(const arg_type &)>::type; template <typename arg_type> result_t<arg_type> operator()(const arg_type & arg) const { return std::sqrt<result_t<arg_type>>(arg).real(); } }; int main() { auto sqrt = phoe::function<sqrt_function>{}; utx::print( (sqrt(arg1))(3), // 1.732051 sqrt(arg1)(5), // 2.236068 sqrt(7)() // 2.645751 ); utx::print((arg1*sqrt(arg1)+arg2)(3,5)); // 10.196152 }
utx::print: https://cppfx.xyz/fx/static/docs/utxcpp/html/utx_print.html
#include <boost/phoenix.hpp> #include <utxcpp/core.hpp> namespace phoe = boost::phoenix; using phoe::arg_names::arg1; using phoe::arg_names::arg2; #include <algorithm> #include <vector> int main() { std::vector<utx::i32> v1(13); utx::i32 value = 0; // std::ranges::for_each std::ranges::for_each(v1, arg1 = phoe::ref(value)++); utx::print_all(v1); // std::count_if utx::print(std::count_if(v1.begin(), v1.end(), arg1%3==0 && arg1%2==0)); // 3 // std::find_if auto itr = std::find_if(v1.begin(), v1.end(), arg1%5==0 && arg1>5); if (itr != v1.end()) { utx::print(*itr); // 10 utx::print(std::ranges::distance(itr, v1.begin())); // -10 } }
#include <boost/phoenix.hpp> #include <utxcpp/core.hpp> namespace phoe = boost::phoenix; using phoe::arg_names::arg1; using phoe::arg_names::arg2; #include <vector> #include <array> class print_all_function { public: using result = void; template <utx::kspt::printable_range ... type_list> result operator()(const type_list & ... value_list) const { utx::print_all(value_list ...); } }; int main() { auto print_all = phoe::function<print_all_function>{}; std::vector<utx::u32> v1{1,2,3,4}; std::array<utx::f32, 3> a1{1.2,2.3,3.4}; print_all(arg1, arg2)(v1, a1); (print_all(arg1, arg2), std::cout << phoe::val("----\n"))(v1, a1); }
utx::print_all: https://cppfx.xyz/fx/static/docs/utxcpp/html/utx_print_all.html
#include <boost/phoenix.hpp> #include <utxcpp/core.hpp> namespace phoe = boost::phoenix; using phoe::arg_names::arg1; using phoe::arg_names::arg2; using phoe::arg_names::arg3; class print_function { public: using result_type = void; template <utx::kspt::printable ... type_list> result_type operator()(const type_list & ... value_list) const { utx::print(value_list ...); } }; int main() { auto print = phoe::function<print_function>{}; print(arg1)(1.2); print(arg1, arg2)("Hello", "World!"); print(arg1, arg2, arg3)(1.2, 3, "Hello"); (print(arg1, arg2, arg3), print("----"))(1,2,3.4,"@+"); }
The local variable acts as an imaginary data-bin where a local, stack based data will be placed.
#include <boost/phoenix.hpp> #include <utxcpp/core.hpp> namespace phoe = boost::phoenix; using phoe::arg_names::arg1; using phoe::arg_names::arg2; using phoe::local_names::_a; using phoe::local_names::_b; using phoe::local_names::_c; using phoe::local_names::_d; int main() { // local names can be used in phoenix::let and phoenix::lambda }
Syntax
let(local-declarations) [ let-body ]
cpp: c++
#include <boost/phoenix.hpp> #include <utxcpp/core.hpp> namespace phoe = boost::phoenix; using phoe::arg_names::arg1; using phoe::arg_names::arg2; using phoe::arg_names::arg3; using phoe::arg_names::arg4; using phoe::let; using phoe::local_names::_a; using phoe::local_names::_b; using phoe::local_names::_x; using phoe::local_names::_y; int main() { let(_x=3, _y=4) [ std::cout << _x << ' ' << _y << '\n' ] (); let(_x=arg1, _y=arg2) [ std::cout << _x << ' ' << _y << '\n', // Hello World let(_x=arg3) [ std::cout << _x << ' ' << _y << '\n' // Boost World ] ] ("Hello", "World", "Boost"); }
Syntax
lambda(local-declarations) [ lambda-body ] lambda [ lambda-body ]
cpp: c++
#include <boost/phoenix.hpp> #include <utxcpp/core.hpp> namespace phoe = boost::phoenix; using phoe::arg_names::arg1; using phoe::arg_names::arg2; using phoe::arg_names::arg3; using phoe::arg_names::arg4; using phoe::lambda; using phoe::local_names::_a; using phoe::local_names::_b; using phoe::local_names::_x; using phoe::local_names::_y; #include <vector> #include <algorithm> int main() { lambda[std::cout << phoe::val(321) << '\n']()(); lambda(_x=phoe::val(123))[std::cout << _x << '\n']()(); lambda[std::cout << arg1 << ' ' << arg2 << '\n']()(12, 3.4); std::vector<utx::i32> v1(12); utx::i32 value = 0; // not good: //std::ranges::for_each(v1, lambda(_x=phoe::ref(value)++)[arg1=_x]()); // good: std::ranges::for_each(v1, lambda(_x=phoe::ref(value))[arg1=_x++]()); std::ranges::for_each(v1, lambda[std::cout << arg1 << ' ']()); std::cout << std::endl; }
#include <boost/phoenix.hpp> #include <iostream> namespace phoenix = boost::phoenix; using phoenix::arg_names::arg1; using phoenix::arg_names::arg2; using phoenix::lambda; using phoenix::local_names::_x; using phoenix::local_names::_y; #include <vector> #include <algorithm> class for_each_lambda { public: using result = void; template <typename container_type, typename function_type> result operator()(container_type & container, const function_type & fn) const { std::ranges::for_each(container, fn); } }; int main() { auto for_each = phoenix::function<for_each_lambda>{}; std::vector<int> v1(12); int x = 1; std::ranges::for_each(v1, arg1 = phoenix::ref(x)++); for_each(arg1, lambda[std::cout << arg1 << ' '])(v1); std::cout << '\n'; }
#include <boost/phoenix.hpp> #include <utxcpp/core.hpp> namespace phoe = boost::phoenix; using phoe::arg_names::arg1; using phoe::arg_names::arg2; using phoe::let; using phoe::construct; using phoe::lambda; using phoe::local_names::_x; using phoe::local_names::_y; #include <vector> #include <algorithm> int main() { std::vector<utx::i32> vector(12); let(_x=construct<utx::i32>(0)) [ generate(arg1, lambda(_x=phoe::ref(_x))[_x++]), for_each(arg1, lambda[std::cout << arg1 << ' ']), std::cout << phoe::val('\n') ] (vector); }
#include <boost/phoenix.hpp> #include <utxcpp/core.hpp> namespace phoe = boost::phoenix; using phoe::arg_names::arg1; using phoe::arg_names::arg2; using phoe::for_; #include <vector> #include <algorithm> #include <random> int main() { utx::u32 index; (for_(phoe::ref(index)=0, phoe::ref(index)<10, phoe::ref(index)++) [std::cout << phoe::ref(index) << ' '], std::cout << phoe::val("\n----\n") )(); //////////////////////////////////////////////////////////////////////// auto rng = std::mt19937{std::random_device{}()}; auto dist = std::uniform_int_distribution<utx::u32>{3,10}; std::vector<utx::u32> vector(7); std::ranges::generate(vector, [&] {return dist(rng);}); using phoe::val; using phoe::ref; std::ranges::for_each(vector, (for_(ref(index)=0,ref(index)<arg1,ref(index)++) [std::cout << arg1 << ' '], std::cout << val('\n') ) ); std::cout << '\n'; }
#include <boost/phoenix.hpp> #include <utxcpp/core.hpp> namespace phoe = boost::phoenix; using phoe::arg_names::arg1; using phoe::arg_names::arg2; using phoe::while_; #include <vector> int main() { std::vector<utx::u32> vector{3,2,4,2,5}; std::ranges::for_each(vector, (while_(arg1-- > 0) [std::cout << arg1 << ' '], std::cout << phoe::val('\n')) ); }
#include <boost/phoenix.hpp> #include <utxcpp/core.hpp> namespace phoe = boost::phoenix; using phoe::arg_names::arg1; using phoe::arg_names::arg2; using phoe::do_; #include <vector> int main() { std::vector<utx::u32> vector{3,2,4,2,5}; std::ranges::for_each(vector, ( do_ [ std::cout << arg1 << ' ' ] .while_(arg1-- > 0), std::cout << phoe::val('\n') ) ); }
#include <boost/phoenix.hpp> #include <utxcpp/core.hpp> namespace phoe = boost::phoenix; using phoe::arg_names::arg1; using phoe::arg_names::arg2; using phoe::if_; #include <vector> #include <numeric> #include <algorithm> int main() { std::vector<utx::u32> vector(12); std::iota(vector.begin(), vector.end(), 1); std::ranges::for_each(vector, if_(arg1%3==0)[arg1*=100]); utx::print_all(vector); }
#include <boost/phoenix.hpp> #include <utxcpp/core.hpp> namespace phoe = boost::phoenix; using phoe::arg_names::arg1; using phoe::arg_names::arg2; using phoe::if_; #include <vector> #include <numeric> #include <algorithm> int main() { std::vector<utx::u32> vector(12); std::iota(vector.begin(), vector.end(), 1); std::ranges::for_each( vector, if_(arg1%3==0) [ std::cout << arg1 << " !!!\n" ] .else_ [ std::cout << arg1 << " ---\n" ] ); }
#include <boost/phoenix.hpp> #include <utxcpp/core.hpp> namespace phoe = boost::phoenix; using phoe::arg_names::arg1; using phoe::arg_names::arg2; using phoe::switch_; using phoe::case_; using phoe::default_; #include <vector> #include <numeric> #include <algorithm> int main() { std::vector<utx::u32> vector(12); std::iota(vector.begin(), vector.end(), 1); std::ranges::for_each( vector, switch_(arg1%5) [ case_<0>(std::cout << arg1 << " ---- 0\n"), case_<1>(std::cout << arg1 << " .... 1\n"), default_(std::cout << arg1 << " *\n") ] ); }
#include <boost/phoenix.hpp> #include <utxcpp/core.hpp> namespace phoe = boost::phoenix; using phoe::arg_names::arg1; using phoe::arg_names::arg2; using phoe::new_; using phoe::delete_; class fizz_t { public: fizz_t(int x, int y, int z) { utx::print("created", x, y, z); } virtual ~fizz_t() { utx::print("removed"); } }; int main() { fizz_t * ptr; utx::print("---"); (arg1=new_<fizz_t>(2,3,4))(ptr); utx::print("*****"); delete_(arg1)(ptr); utx::print("!!!!!!!!!"); }
#include <boost/phoenix.hpp> #include <utxcpp/core.hpp> namespace phoe = boost::phoenix; using phoe::arg_names::arg1; using phoe::arg_names::arg2; using phoe::arg_names::arg3; using phoe::local_names::_x; using phoe::local_names::_y; class fizz { public: float x{12.3}; float sum(float a, float b) const { return a+b; } }; int main() { fizz f1; utx::print( phoe::bind(&fizz::x, arg1)(f1), // 12.3 phoe::bind(&fizz::x, f1)(), // 12.3 phoe::bind(&fizz::sum, arg1, arg2, arg3)(f1, 1.1, 2.3), // 3.4 phoe::bind(&fizz::sum, f1, 1.2, 2.4)() // 3.6 ); }
#include <boost/phoenix.hpp> #include <utxcpp/core.hpp> namespace phx = boost::phoenix; using phx::arg_names::arg1; using phx::arg_names::arg2; using phx::local_names::_x; using phx::local_names::_y; using phx::if_else; #include <vector> #include <numeric> #include <algorithm> int main() { std::vector<utx::i32> vector(16); std::iota(vector.begin(), vector.end(), 1); std::ranges::for_each(vector, if_else(arg1%3==0, arg1=arg1*1000, arg1=arg1*10)); utx::print_all(vector); }
#include <boost/phoenix.hpp> #include <utxcpp/core.hpp> namespace phx = boost::phoenix; using phx::arg_names::arg1; using phx::arg_names::arg2; using phx::if_; using phx::val; #include <vector> #include <numeric> #include <algorithm> int main() { std::vector<utx::i32> vector(100); std::iota(vector.begin(), vector.end(), 1); std::ranges::for_each( vector, if_(arg1%15==0) [ std::cout << val("fizzbuzz ") ] .else_ [ if_(arg1%3==0) [ std::cout << val("fizz ") ] .else_ [ if_(arg1%5==0) [ std::cout << val("buzz ") ] .else_ [ std::cout << val(arg1) << ' ' ] ] ] ); std::cout << std::endl; }
#include <boost/phoenix.hpp> #include <utxcpp/core.hpp> namespace phx = boost::phoenix; using phx::arg_names::arg1; using phx::arg_names::arg2; using phx::if_else; using phx::val; #include <vector> #include <numeric> #include <algorithm> int main() { std::vector<utx::i32> vector(100); std::iota(vector.begin(), vector.end(), 1); std::ranges::for_each( vector, if_else(arg1%15==0, std::cout << val("fizzbuzz "), if_else(arg1%3==0, std::cout << val("fizz "), if_else(arg1%5==0, std::cout << val("buzz "), std::cout << val(arg1) << ' ' ) ) ) ); std::cout << std::endl; }
#include <boost/phoenix.hpp> #include <utxcpp/core.hpp> namespace phx = boost::phoenix; using phx::arg_names::arg1; using phx::arg_names::arg2; int main() { // phoenix::transform utx::i32 ar1[] = {1,2,3,4,5,6,7}; const auto size = sizeof ar1/sizeof ar1[0]; auto itr = phx::transform(arg1, arg2, phx::lambda[arg1*=arg1])(ar1, ar1); utx::print_all(ar1); // 1 4 9 16 25 36 49 utx::rt_assert(itr == ar1+size, "itr == ar1+size"); // phoenix::copy utx::i32 ar2[size]; auto itr2 = phx::copy(arg1, arg2)(ar1, ar2); utx::print_all(ar2); // 1 4 9 16 25 36 49 utx::rt_assert(itr2 == ar2+size); // phoenix::fill utx::i32 ar3[size]; phx::fill(arg1, arg2)(ar3, 9); utx::print_all(ar3); // 9 9 9 9 9 9 9 // phoenix::rotate phx::rotate(arg1, arg2)(ar2, ar2+3); utx::print_all(ar2); // 16 25 36 49 1 4 9 }
#include <boost/phoenix.hpp> #include <utxcpp/core.hpp> namespace phx = boost::phoenix; using phx::arg_names::arg1; using phx::arg_names::arg2; using phx::arg_names::arg3; #include <vector> int main() { utx::u32 v1[] = {1,2,3}; utx::u32 v2[] = {4,5,6,7}; utx::u32 v3[std::size(v1)+std::size(v2)]; // phoenix::merge auto itr = phx::merge(arg1, arg2, arg3)(v1, v2, v3); utx::print_all(v3); // 1 2 3 4 5 6 7 utx::rt_assert(itr == v3 + sizeof v3/sizeof v3[0]); // phoenix::reverse phx::reverse(arg1)(v3); utx::print_all(v3); // 7 6 5 4 3 2 1 // phoenix::sort utx::u32 v4[] = {3,1,2,5,9,7,4}; utx::print_all(v4); // 3 1 2 5 9 7 4 phx::sort(arg1)(v4); utx::print_all(v4); // 1 2 3 4 5 7 9 }
#include <boost/phoenix.hpp> #include <utxcpp/core.hpp> #include <vector> namespace phx = boost::phoenix; using phx::arg_names::arg1; using phx::arg_names::arg2; using phx::arg_names::arg3; #include <algorithm> int main() { // phoenix::for_each std::vector<utx::i32> v1{2,3,1,4,5,7}; phx::for_each(arg1, phx::lambda[std::cout << arg1 << ' '])(v1); std::cout << std::endl; // std::ranges::for_each std::ranges::for_each(v1, std::cout << arg1 << ' '); std::cout << "\n----\n"; std::vector<std::vector<utx::u32>> v2 { {1,2,3}, {4,5,6,7}, {3,4}, {1,2,3,4,5,6,7,8,9}, {3,2,1,0} }; // Nested For Each: std::ranges::for_each and phoenix::for_each std::ranges::for_each(v2, (phx::for_each(arg1, phx::lambda[std::cout << arg1 << ' ']), std::cout << phx::val('\n') ) ); }
#include <boost/phoenix.hpp> #include <utxcpp/core.hpp> #include <vector> namespace phx = boost::phoenix; using phx::arg_names::arg1; using phx::arg_names::arg2; using phx::arg_names::arg3; int main() { std::vector<utx::i32> v1{4,2,3,1,5,9,7}; // phoenix::find auto itr = phx::find(arg1, arg2)(v1, 5); if (itr != v1.end()) utx::print(*itr); // 5 utx::rt_assert(itr == v1.begin()+4); // phoenix::search std::vector<utx::i32> v2{3,1,5}; itr = phx::search(arg1, arg2)(v1, v2); utx::rt_assert(itr != v1.end(), "itr != v1.end()"); utx::rt_assert(itr == v1.begin() + 2, "itr == v1.begin() + 2"); // phoenix::search std::vector<utx::i32> v3{9,6}; itr = phx::search(arg1, arg2)(v1, v3); utx::rt_assert(itr == v1.end(), "itr == v1.end()"); // phoenix::distance utx::rt_assert(std::cmp_equal( phx::distance(arg1)(v1), v1.size() )); utx::i32 a1[] = {1,2,3}; utx::i32 a2[] = {1,2,3}; // phoenix::equal utx::rt_assert( phx::equal(arg1, arg2)(a1, a2) ); utx::i32 a3[] = {1,2,3,7,4,5}; utx::i32 a4[] = {1,2,3, 9, 8}; // phoenix::mismatch auto p1 = phx::mismatch(arg1, arg2)(a3, a4); utx::rt_assert(p1 == std::make_pair(a3+3, a4+3), "p1 == std::make_pair(a3+3, a4+3)"); utx::print_all(std::span{p1.first, a3+std::size(a3)}); // 7 4 5 utx::print_all(std::span{p1.second, a4+std::size(a4)}); // 9 8 }
#include <boost/phoenix.hpp> #include <utxcpp/core.hpp> #include <vector> namespace phx = boost::phoenix; using phx::arg_names::arg1; using phx::arg_names::arg2; using phx::arg_names::arg3; using phx::local_names::_x; int main() { bool value = false; std::string msg; phx::try_ [ phx::throw_(std::runtime_error{"test exception"}) ] .catch_<std::exception &>(_x) [ phx::ref(value) = true ](); utx::print(value); // true }
Lazy evaluation is an evaluation strategy which delays the evaluation of an expression until its value is needed.
+ - * / ref val
CPP: c++
#include <boost/phoenix.hpp> #include <utxcpp/core.hpp> #include <vector> namespace phx = boost::phoenix; using phx::arg_names::arg1; using phx::arg_names::arg2; int main() { arg1+arg2; // Lazy arg1*arg2; // Lazy float x=1.2; phx::ref(x)=3.1; // Lazy utx::print(x); // 1.2 x = 4.1; // Immediate utx::print(x); // 4.1 std::vector<utx::i32> v1(7); phx::ref(v1)[0]; // Lazy v1[0]; // Immediate }
#include <boost/phoenix.hpp> #include <utxcpp/core.hpp> #include <vector> namespace phx = boost::phoenix; using phx::arg_names::arg1; using phx::arg_names::arg2; using namespace utx::string_literals; int main() { // Lazy Statement phx::if_(true) [ std::cout << arg1 << ' ', std::cout << arg2 << '\n' ]; phx::if_(true) [ std::cout << arg1 << ' ', std::cout << arg2 << '\n' ] (123, "boost::phoenix"_us); }
utx::string: https://cppfx.xyz/fx/static/docs/utxcpp/html/utx_string.html
#include <boost/phoenix.hpp> #include <utxcpp/core.hpp> #include <vector> #include <algorithm> namespace phx = boost::phoenix; using phx::arg_names::arg1; using phx::arg_names::arg2; class is_even_impl { public: using result_type = bool; template <std::integral type_t> result_type operator()(const type_t & value) const { return value%2==0; } }; // Lazy Function auto is_even = phx::function<is_even_impl>{}; int main() { // Lazy is_even(23); // Lazy is_even(arg1); // false true false utx::print(is_even(arg1)(23), is_even(arg1)(32), is_even(phx::val(17))()); std::vector<utx::i32> v1{1,2,3,4,5}; auto even_count = std::count_if(v1.begin(), v1.end(), is_even(arg1)); utx::print(even_count); // 2 }
Last revised: March 27, 2023 at 03:21:19 GMT |