【发布时间】:2010-05-19 17:16:17
【问题描述】:
Boost lambda 允许使用ret<T> 模板覆盖推导的返回类型。
我曾尝试在 phoenix 中搜索等价物,但找不到。
凤凰有等价物吗?我知道如何制作自己的替代品,但我宁愿不这样做。谢谢
【问题讨论】:
标签: c++ boost-spirit boost-lambda boost-phoenix
Boost lambda 允许使用ret<T> 模板覆盖推导的返回类型。
我曾尝试在 phoenix 中搜索等价物,但找不到。
凤凰有等价物吗?我知道如何制作自己的替代品,但我宁愿不这样做。谢谢
【问题讨论】:
标签: c++ boost-spirit boost-lambda boost-phoenix
重写:我的第一个答案错过了重点(太晚了),让我再试一次。
让我为像我这样第一次可能会错过你的观点的人做一些说明。在 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 替代品,但从某种意义上说,它更好,因为它是全球性的。如果有很多运算符需要重载,则可以将整个操作集宏化。
【讨论】:
AFAIK,Phoenix 不支持这个(或类似的东西)。不过,如果您描述了您的用例,我可能会提供帮助。
【讨论】: