The answer is really very simple and you're going to kick yourself. The expression transformation you wrote knows how to convert a plus node into a subtract node. But there is no plus node in the expression you're passing to it. Look again:
auto g = invrt()(phoenix::lambda(_a = 0)[my_add(_1,_2)]);
Where's the plus node? To Proto (and to Phoenix), my_add
is opaque. They don't know there's an addition going on inside there. How could they?
====EDIT====
Consider this instead, which does what you intend:
#include <iostream>
#include <boost/phoenix.hpp>
#include <boost/proto/proto.hpp>
namespace proto = boost::proto;
namespace phoenix = boost::phoenix;
using namespace phoenix::arg_names;
using namespace phoenix::local_names;
auto const my_add = phoenix::let(_a = _1, _b = _2)[_a + _b];
struct invrt:
proto::or_<
proto::when<
proto::plus<proto::_, proto::_>,
proto::functional::make_expr<proto::tag::minus>(
invrt(proto::_left), invrt(proto::_right)
)
>,
proto::otherwise<
proto::nary_expr<proto::_, proto::vararg<invrt> >
>
>
{};
int main()
{
auto f = phoenix::lambda(_a = 0)[my_add(_1,_2)];
auto g = invrt()(phoenix::lambda(_a = 0)[my_add(_1,_2)]);
std::cout << f()(1,2) << std::endl; // 3
std::cout << g()(1,2) << std::endl; // -1, w00t!
}