Rewrite: I missed the point on my first answer (it was late), let me try again.
Let me give some exposition for people like me who might miss your point the first time. In boost::lambda, when using user defined types in operator expressions, one has to use the ret<> function to override return type deduction. This is because the lambda return type deduction system only supports native (and stl? I don't remember) types directly. A short example:
using namespace boost::lambda;
struct add_t{
add_t(int i) : i(i) {};
add_t operator+(const add_t& other) const{
return add_t(i + other.i);
}
int i;
};
(_1 + _2)(add_t(38), add_t(4)); // RETURN TYPE DEDUCTION FAILS
ret<add_t>(_1 + _2)(add_t(38), add_t(4)); // OK
In phoenix though, no hints are are needed (note that literals and non-const temporaries cannot appear in a phoenix argument list):
using namespace boost::phoenix;
add_t i(38), j(4);
(_1 + _2)(i, j); // JUST FINE
The return type deduction system is completely different and much more natural in phoenix; it will properly deduce the return type of operators that use conventional semantics. Specifically, the return type should match the type of one of the operands, be a reference, pointer, or const pointer to one of the argument types, or be an stl container/container iterator of one of those types. There is a nice write up of phoenix return type deduction in type_deduction.hpp header for more details.
So now I'm reading your question as, how can non-conventional operator semantics be handled in phoenix?
Consider the following strange pair of types as an example
struct add_ret_t{
add_ret_t(int i) : i(i) {};
int i;
};
struct add_t{
add_t(int i) : i(i) {};
add_ret_t operator+(const add_t& other) const{
return add_ret_t(i + other.i);
}
int i;
};
For lambda, this is no problem, just use the ret function:
using namespace boost::lambda;
ret<add_ret_t>(_1 + _2)(add_t(38), add_t(4)); // OK
But phoenix can't deal with this operator (can you blame it?) because the return type is not related to the arguments, and there is no way to directly indicate the return type in phoenix. If there is a good reason to use an operator like this, a case could be added to the type deduction system, but I can't see a way to do this without hacking type_deduction.hpp or branching a good portion of phoenix.
Alternatively, I figured out a little hack to override the return types for specific operators. The result_of_operation template structures in boost/spirit/home/phoenix/operator/arithmetic.hpp (lines 39-56 list the struct types, boost 1.43) execute the type deduction when they are instantiated and store the result. So all that is needed is to provide some template specializations for the problem operations, which only need contain one typedef specifying the return type. Example (codepad for full src):
using namespace boost::phoenix;
namespace boost{ namespace phoenix{
//override add_t addition to give add_ret_t
template <> struct result_of_plus<add_t&, add_t&> { typedef add_ret_t type; };
//override int addition to give char
template <> struct result_of_plus<int&, int&> { typedef char type; };
}}
int main()
{
add_t i = 1, j = 7;
std::cout << ((_1 + _2)(i, j)).i << std::endl;
int k = 51, l = 37;
std::cout << ((_1 + _2)(k, l)) << std::endl;
return 0;
}
This certainly isn't a ret replacement, but in some senses its better since its global. If there are a lot of operators to overload, the full set of operations could be macroed.