简体   繁体   English

我的boost phoenix延迟功能有什么问题?

[英]What's wrong with my boost phoenix lazy function?

I have the following code (using boost 1.55 on MSVC9): 我有以下代码(在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);
}

I'm getting a compiler error regarding pair_first_impl::result::type , which says: 我收到关于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> )
        ]

For some reason, it looks like it is passing in a function type (?) into my TPair template argument instead of the std::pair type directly. 出于某种原因,它似乎将函数类型(?)传递给了我的TPair模板参数,而不是直接传递给std::pair类型。

Can anyone help me figure out what I'm doing wrong here? 有人可以帮我弄清楚我在做什么错吗?

I found the solution by reviewing the result_of protocol documentation (which is separate from phoenix; I was expecting phoenix docs to explain): 我通过查看协议文档的result_of协议找到了解决方案(与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;
}

The problem was that I thought that the type passed into the template parameter for the nested result struct was the type of the first parameter, which it isn't. 问题是我认为传递给嵌套result结构的template参数的类型是第一个参数的类型,不是。 It's actually the whole function type. 它实际上是整个函数类型。 So a template specialization of result must be created the can be used to extract the type of the first argument. 因此,必须创建result的模板专用化,才能用于提取第一个参数的类型。 You can then use this to access first_type in the pair. 然后,您可以使用它访问first_type中的first_type

My _1 placeholder is valid because at the top of my source file I'm doing the following: 我的_1占位符有效,因为在源文件的顶部,我正在执行以下操作:

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

You're using the wrong placeholder _1 . 您使用了错误的占位符_1 You need one that is actually a phoenix actor: 您需要一个实际上是凤凰演员的人:

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

OTOH, your functor has inconsistent result_type protocol. OTOH,您的函子的result_type协议不一致。 This might not bite you when you use BOOST_SPIRIT_RESULT_OF_USE_DECLTYPE . 当您使用BOOST_SPIRIT_RESULT_OF_USE_DECLTYPE时,这可能不会咬您。 Why don't you just use a bind ? 您为什么不只使用bind This will get all the deduction correct for you without the work: 这将使您无需工作即可获得所有正确的扣除额:

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

Of course, you can detect the pair-type if you want. 当然,您可以根据需要检测配对类型。

Full code Live On Coliru 完整代码Live On 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();
}

This doesn't answer your question, but it gives a workaround that is based on existing implementation: (untested code) 这不会回答您的问题,但是会提供一种基于现有实现的解决方法:(未经测试的代码)

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

(This without even mention that with C++11 Lambdas you don't need any of this) (这甚至没有提到使用C ++ 11 Lambdas,您不需要任何这些)

Even if this works, your question is a valid one. 即使这有效,您的问题也是有效的。 I suggest two experiments, 1) use enable_if to discard TPair if it is a phoenix expression. 我建议进行两个实验,1)如果它是凤凰表达式,请使用enable_if丢弃TPair 2) Make your operator() more specific to std::pair , like this: 2)使您的operator()更特定于std::pair ,如下所示:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM