我的助推凤凰懒惰功能有什么问题?

What's wrong with my boost phoenix lazy function?

本文关键字:什么 问题 功能 凤凰 我的      更新时间:2023-10-16

我有以下代码(在MSVC9上使用boost 1.55(:

struct pair_first_impl
{
   template<class TPair> struct result { typedef typename TPair::first_type type; };
   template<class TPair>
   typename TPair::first_type const& operator() (TPair const& pair) const
   {
      return pair.first;
   }
   template<class TPair>
   typename TPair::first_type& operator() (TPair& pair)
   {
      return pair.first;
   }
};
static phx::function<pair_first_impl> pair_first;
int test()
{
   std::map<int, std::string> mymap;
   std::find_if(mymap.begin(), mymap.end(), pair_first(_1) == 1);
}

我收到一个关于pair_first_impl::result::type的编译器错误,上面写着:

error C2825: 'TPair': must be a class or namespace when followed by '::'
see reference to class template instantiation 'pair_first_impl::result<TPair>' being compiled
        with
        [
            TPair=const pair_first_impl (std::pair<const int,std::string> )
        ]

出于某种原因,它看起来像是将函数类型(?(传递到我的TPair模板参数中,而不是直接传递到std::pair类型中。

有人能帮我弄清楚我在这里做错了什么吗?

我通过查看协议文档的结果找到了解决方案(它与phoenix是分开的;我希望phoenix文档能解释(:

struct pair_first_impl
{
   template<class> struct result;
   template<class F, class TPair>
   struct result<F(TPair)>
   {
      typedef typename boost::remove_reference<TPair>::type actual_type;
      typedef typename actual_type::first_type type;
   };
   template<class TPair>
   typename TPair::first_type const& operator() (TPair const& pair) const
   {
      return pair.first;
   }
   template<class TPair>
   typename TPair::first_type& operator() (TPair& pair)
   {
      return pair.first;
   }
};
static phx::function<pair_first_impl> pair_first;
int test()
{
   std::map<int, std::string> mymap;
   std::find_if(mymap.begin(), mymap.end(), pair_first(_1) == 1);
   return 0;
}

问题是,我认为传递到嵌套result结构的模板参数中的类型是第一个参数的类型,但事实并非如此。它实际上是整个函数类型。因此,必须创建result的模板专用化,才能用于提取第一个参数的类型。然后,您可以使用它来访问对中的first_type

我的_1占位符是有效的,因为在源文件的顶部,我正在执行以下操作:

using namespace boost::phoenix::placeholders;
namespace phx = boost::phoenix;

您使用了错误的占位符_1。你需要一个真正的凤凰演员:

std::find_if(mymap.begin(), mymap.end(), pair_first(phx::placeholders::_1) == 1);

OTOH,您的函数具有不一致的result_type协议。当你使用BOOST_SPIRIT_RESULT_OF_USE_DECLTYPE时,这可能不会咬你。你为什么不直接用bind呢?这将使你在没有工作的情况下得到所有正确的推断:

using namespace phx::arg_names;
void test()
{
   std::map<int, std::string> mymap;
   using Pair = std::pair<const int, std::string>;
   std::find_if(mymap.begin(), mymap.end(), phx::bind(&Pair::first, arg1) == 1);
}

当然,如果您愿意,您可以检测配对类型。

完整代码Coliru直播

#include <boost/phoenix.hpp>
#include <algorithm>
#include <map>
namespace phx = boost::phoenix;
struct pair_first_impl
{
   template<class TPair> struct result { typedef typename TPair::first_type const& type; };
   template<class TPair>
   typename TPair::first_type const& operator() (TPair const& pair) const {
      return pair.first;
   }
   template<class TPair>
   typename TPair::first_type& operator() (TPair& pair) {
      return pair.first;
   }
};
static phx::function<pair_first_impl> pair_first;

void test1()
{
   using phx::placeholders::_1;
   std::map<int, std::string> mymap;
   std::find_if(mymap.begin(), mymap.end(), pair_first(_1) == 1);
}
void test2()
{
   using Pair = std::pair<const int, std::string>;
   using namespace phx::arg_names;
   std::map<int, std::string> mymap;
   std::find_if(mymap.begin(), mymap.end(), phx::bind(&Pair::first, arg1) == 1);
}
void test3()
{
   std::map<int, std::string> mymap;
   using Pair = decltype(mymap)::value_type;
   using namespace phx::arg_names;
   std::find_if(mymap.begin(), mymap.end(), phx::bind(&Pair::first, arg1) == 1);
}
int main()
{
    test1();
    test2();
    test3();
}

这并不能回答您的问题,但它提供了一个基于现有实现的变通方法:(未经测试的代码(

#include <boost/fusion/adapted/std_pair.hpp>
#include <boost/phoenix/fusion/at.hpp>
...
int test()
{
   std::map<int, std::string> mymap;
   std::find_if(mymap.begin(), mymap.end(), boost::phoenix::at_c<0>(_1) == 1);
}

(这甚至没有提到,使用C++11 Lambdas,你不需要任何这些(

即使这有效,你的问题也是有效的。我建议进行两个实验,1( 如果是phoenix表达式,则使用enable_if来丢弃TPair。2( 使您的operator()更特定于std::pair,如下所示:

   ...
   template<class T1, T2> // change `result` accordingly.
   T1& operator() (std::pair<T1, T2>& pair)
   {
      return pair.first;
   }
   ...