gpt4 book ai didi

c++ - 是否有可能让 Phoenix 对二元运算符的贪婪程度降低一个档次?

转载 作者:行者123 更新时间:2023-11-30 05:43:06 27 4
gpt4 key购买 nike

我想要一个通过二元运算符获取(未计算的)Phoenix 表达式的类类别。基本上这个想法是类处理表达式,例如,将表达式打印到屏幕。

问题是 Phoenix 重载了所有二元运算符,除非存在精确匹配,否则 Phoenix(惰性)运算符是首选。 是否有可能让 Phoenix 在劫持运营商方面不那么贪心?

示例代码:

#include<boost/phoenix.hpp>
#include<iostream>
namespace mylib{
template<class T>
struct myclass{};

template<class P, class T>
auto operator<<(
myclass<P>& p,
boost::phoenix::actor<
boost::proto::exprns_::basic_expr<
boost::proto::tagns_::tag::terminal,
boost::proto::argsns_::term<T>,
0l
>
> const& t
)->decltype(p){return p << "expression[" << t() << "]";}

}

int main(){
mylib::myclass<int> A;
A << boost::phoenix::val(3.); // Doesn't work as expected. Generates a Phoenix `shift``<<` expression. Not the desired outcome.
mylib::operator<<(A, boost::phoenix::val(3.)); // works as expected
}

一个解决方案是不要重载二元运算符,但问题更多的是如何让 Phoenix 不那么贪婪。


编辑:惯用的解决方法,hold 函数:

在几次不成功的尝试之后,我改变了我的看法,这似乎是一个坏主意,因为必须与 Phoenix/Proto 系统进行激烈的斗争,其中每个 C++ 表达式都解释为构建一个 Phoenix 表达式。所以,我决定定义一个暂时离开凤凰世界的函数,带hold函数。

namespace boostx{ // warning: the attempt to deal with rvalues in this code could be wrong, feedback is welcomed
namespace phoenixx{
template<class T> struct held{
T release_;
decltype(auto) release(){return release_;}
decltype(auto) release() const{return release_;}
friend decltype(auto) release(held& ht){return ht.release();}
friend decltype(auto) release(held const& ht){return ht.release();}
};

template<class T, typename = std::enable_if_t<boost::phoenix::is_actor<std::decay_t<T>>::value> >
held<T> hold(T&& t){
return {std::forward<T>(t)};
}
}}

(也许Phoenix中已经存在(或应该存在)这样的功能,它是对actor类的补充。)

然后库有一个特殊的重载来处理这个持有的对象,它在正确的上下文中released。

namespace mylib{
... same as before, plus this new overload ...
template<class P, class Actor>
auto operator<<(
myclass<P>& p,
boostx::phoenixx::held<Actor> const& ha
)->decltype(p){
return mylib::operator<<(p, ha.release());
}
}

最后,这有效:

int main(){
mylib::myclass<int> A;
A << hold(boost::phoenix::val(3.));
mylib::operator<<(A, boost::phoenix::val(3.)); // works as expected
}

据我所知,其他函数式语言最终需要这种函数来暂停急切的表达式简化或构造。例如:https://reference.wolfram.com/language/ref/Hold.html

欢迎提供反馈。

最佳答案

总的来说,我认为使用 Proto Transform 可以更好地完成您想要实现的目标。

具体来说,您要对抗的是 ADL。并且没有办法让 Proto 对此“不那么贪婪”,因为它是一种语言机制[1]

但是,ADL 也应该拉入 mylib::operator<< .给了什么?

修复

您的重载需要 Actor const& .但是请注意,如果它可以被非 const 引用获取,则该重载将是首选。您可以按值(value)和利润来获取它:

Live On Coliru

#include<boost/phoenix.hpp>
#include<iostream>

namespace mylib{

template<class T>
struct myclass{};

template<class P, class T>
auto operator<<(
myclass<P>& p,
boost::phoenix::actor<
boost::proto::exprns_::basic_expr<
boost::proto::tagns_::tag::terminal,
boost::proto::argsns_::term<T>,
0l
>
> t
)->decltype(p){
std::cout << __PRETTY_FUNCTION__ << " arg: " << t() << "\n";
return p; // << "expression[" << t() << "]";
}
}

int main(){
mylib::myclass<int> A;
A << boost::phoenix::val(3.);
}

具有通用引用的版本可能更清晰:

Live On Coliru

template<class P, class Actor>
auto operator<<(myclass<P>& p, Actor&& t) -> decltype(p) {
std::cout << __PRETTY_FUNCTION__ << " arg: " << t() << "\n";
return p;
}

您可以使用标签调度或 SFINAE 进一步选择特定类型的 Actor

关于c++ - 是否有可能让 Phoenix 对二元运算符的贪婪程度降低一个档次?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30314372/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com