PrevUpHomeNext

Home:: tiv.cc

boost::phoenix in OnePage


boost::phoenix

boost::phoenix in OnePage

boost::phoenix Quick Look in OnePage

boost::phoenix Tutorial in OnePage

boost::phoenix::arg_names: argument placeholders

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';
}

phoenix::val and phoenix::ref

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
}

phoenix::function

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

std::for_each(std::ranges::for_each), std::count_if and std::find_if

#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
	}
}

utx::print_all and phoenix::function

#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

utx::print and phoenix::function

#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,"@+");
}

phoenix::local_names: local variables, predefined local variables

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
}

phoenix::let

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");
}

phoenix::lambda

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;
}

phoenix::lambda for each

#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';
}

generator, for_each

#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);
}

phenix::for_

#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';
}

phenix::while_

#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'))
	);
}

do_ ... while_

#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')
		)
	);
}

phoenix::if_

#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);
}

if_ ... else_

#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"
		]
	);
}

phoenix::switch_

#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")
		]
	);
}

phoenix::new_, phoenix::delete_

#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("!!!!!!!!!");
}

phoenix::bind: bind members

#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
	);
}

phoenix::if_else

#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);
}

fizz-buzz: nested if_ else_

#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;
}

fizz-buzz: nested if_else

#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;
}

transformation algorithms: phoenix::transform, phoenix::copy, phoenix::fill, phoenix::rotate

#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
}

transformation algorithms: phoenix::merge, phoenix::reverse

#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
}

algorithms: phoenix::for_each, std::ranges::for_each, nested for-each

#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')
		)
	);
}

algorithms: phoenix::find, phoenix::search, phoenix::distance, phoenix::equal, phoenix::mismatch

#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
}

phoenix exception

#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
}

boost::phoenix Lazy Evaluation

Lazy evaluation is an evaluation strategy which delays the evaluation of an expression until its value is needed.

Lazy Operators
+
-
*
/
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
}
Lazy Statements
#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

Lazy Functions
#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


PrevUpHomeNext