开发者

C++ boost::lambda::ret equivalent in phoenix

Boost lambda allows to overwrite deduced return type using ret<T> template. I have tried searching for equivalent in phoenix but could not find one.

Is there an equivalent in phoenix? I know how to make my own Replacement but I would r开发者_StackOverflow社区ather not. thank you


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.


AFAIK, this (or something similar) is not supported in Phoenix. If you described your use case I might be able to help, though.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜