【问题标题】:C++ boost::lambda::ret equivalent in phoenix凤凰城中的 C++ boost::lambda::ret 等价物
【发布时间】:2010-05-19 17:16:17
【问题描述】:

Boost lambda 允许使用ret<T> 模板覆盖推导的返回类型。 我曾尝试在 phoenix 中搜索等价物,但找不到。

凤凰有等价物吗?我知道如何制作自己的替代品,但我宁愿不这样做。谢谢

【问题讨论】:

    标签: c++ boost-spirit boost-lambda boost-phoenix


    【解决方案1】:

    重写:我的第一个答案错过了重点(太晚了),让我再试一次。

    让我为像我这样第一次可能会错过你的观点的人做一些说明。在 boost::lambda 中,当在运算符表达式中使用用户定义类型时,必须使用 ret 函数来覆盖返回类型推导。这是因为 lambda 返回类型推演系统只直接支持 native(还有 stl?我不记得了)类型。一个简短的例子:

    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
    

    不过,在 phoenix 中,不需要任何提示(注意文字和非常量临时变量不能出现在 phoenix 参数列表中):

    using namespace boost::phoenix;
    
    add_t i(38), j(4);
    (_1 + _2)(i, j);    // JUST FINE
    

    返回类型的扣除系统在phoenix中完全不同并且更自然;它将正确推断使用常规语义的运算符的返回类型。具体来说,返回类型应该与其中一个操作数的类型匹配,可以是指向其中一种参数类型的引用、指针或 const 指针,或者是其中一种类型的 stl 容器/容器迭代器。 type_deduction.hpp header 中有一篇很好的关于凤凰返回类型推导的文章,了解更多详情。

    所以现在我将您的问题解读为,如何在 phoenix 中处理非常规运算符语义?

    以下面这对奇怪的类型为例

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

    对于 lambda,这没问题,只需使用 ret 函数即可:

    using namespace boost::lambda;
    
    ret<add_ret_t>(_1 + _2)(add_t(38), add_t(4)); // OK
    

    但是phoenix不能处理这个操作符(能怪它吗?),因为返回类型与参数无关,在phoenix中也没有办法直接指明返回类型。如果有充分的理由使用这样的运算符,则可以将案例添加到类型推导系统中,但如果不破解 type_deduction.hpp 或分支 phoenix 的大部分内容,我看不到这样做的方法。

    另外,我想出了一个小技巧来覆盖特定运算符的返回类型。 boost/spirit/home/phoenix/operator/arithmetic.hpp 中的 result_of_operation 模板结构(第 39-56 行列出了结构类型,boost 1.43)在实例化时执行类型推导并存储结果。所以只需要为问题操作提供一些模板特化,只需要包含一个 typedef 指定返回类型。示例(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;
    }
    

    这当然不是 ret 替代品,但从某种意义上说,它更好,因为它是全球性的。如果有很多运算符需要重载,则可以将整个操作集宏化。

    【讨论】:

      【解决方案2】:

      AFAIK,Phoenix 不支持这个(或类似的东西)。不过,如果您描述了您的用例,我可能会提供帮助。

      【讨论】:

        猜你喜欢
        • 2015-09-06
        • 2016-05-03
        • 1970-01-01
        • 2017-07-21
        • 1970-01-01
        • 1970-01-01
        • 2018-11-27
        • 2016-12-24
        • 1970-01-01
        相关资源
        最近更新 更多