Skip to main content

Updated May 4, 2026

Boost.Phoenix

Boost.Phoenix is a functional-programming toolkit for C++ that lets you build function objects inline using expression templates. Before C++11 lambdas existed, Phoenix provided the closest thing the language had to anonymous functions — lazy expressions composed from placeholders, operators, and higher-order combinators. Today it remains relevant as the expression layer behind Boost.Spirit semantic actions.

The problem it solves

Pre-C++11 C++ had no lambdas. Writing a one-off functor for std::for_each or a Spirit semantic action meant declaring a whole class. Phoenix lets you write _1 * _1 + 1 directly in the algorithm call, producing a function object at compile time through expression templates.

Lazy expressions with placeholders​

Phoenix placeholders (arg1, arg2, ...) build callable expression trees that are evaluated later, when the resulting function object is invoked.

phoenix_basics.cpp
#include <boost/phoenix.hpp>
#include <algorithm>
#include <vector>
#include <iostream>

int main() {
using namespace boost::phoenix;
using namespace boost::phoenix::placeholders;

std::vector<int> v{1, 2, 3, 4, 5};

// Square each element — _1 * _1 builds a lazy function object
std::vector<int> result;
std::transform(v.begin(), v.end(), std::back_inserter(result),
arg1 * arg1);

for (int x : result) std::cout << x << " ";
// 1 4 9 16 25
}

Lazy values and references​

val() wraps a constant into a lazy expression; ref() wraps a reference so that the expression can read or mutate external state.

phoenix_val_ref.cpp
#include <boost/phoenix.hpp>
#include <algorithm>
#include <vector>
#include <iostream>

int main() {
using namespace boost::phoenix;
using namespace boost::phoenix::placeholders;

std::vector<int> v{1, 2, 3, 4, 5};

int total = 0;
std::for_each(v.begin(), v.end(), ref(total) += arg1);
std::cout << "sum = " << total << "\n"; // 15
}

Control-flow expressions​

Phoenix provides lazy versions of if_else_, while_, for_, and switch_ for building complex inline expressions.

phoenix_control.cpp
#include <boost/phoenix.hpp>
#include <algorithm>
#include <vector>
#include <iostream>

int main() {
using namespace boost::phoenix;
using namespace boost::phoenix::placeholders;

std::vector<int> v{-2, 5, -1, 3, 0};

// Clamp negatives to zero
std::transform(v.begin(), v.end(), v.begin(),
if_else_(arg1 < val(0), val(0), arg1));

for (int x : v) std::cout << x << " ";
// 0 5 0 3 0
}

Phoenix with Boost.Spirit​

Phoenix's main modern use case is as the semantic-action engine for Spirit parsers. Spirit rules produce attributes; Phoenix expressions transform them inline.

phoenix_spirit.cpp
#include <boost/spirit/include/qi.hpp>
#include <boost/phoenix.hpp>
#include <iostream>
#include <string>

int main() {
namespace qi = boost::spirit::qi;
using boost::phoenix::ref;

std::string input = "42";
int result = 0;

qi::parse(input.begin(), input.end(),
qi::int_[ref(result) = qi::_1]);

std::cout << result << "\n"; // 42
}
When Phoenix still matters

If you use Boost.Spirit, you will encounter Phoenix — it is the standard way to write semantic actions. Outside of Spirit, C++11 lambdas are almost always a better choice.

Phoenix versus lambdas​

FeatureBoost.PhoenixC++ Lambdas
Availablepre-C++11C++11+
Syntaxexpression templates (arg1 * arg1)[](auto x) { return x * x; }
Composabilityvery high (expression trees)moderate (nesting)
Debuggabilitypoor (deep template errors)good
Spirit integrationnativeworks but more verbose
Learning curvesteeplow
Legacy status

Phoenix was essential before C++11. In modern C++ it is a niche tool — reach for it when working with Spirit, and prefer lambdas everywhere else.

See also​