我的提升凤凰懒惰功能有什么问题?

时间:2014-03-23 15:30:44

标签: c++ boost boost-phoenix

我有以下代码(在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类型。

任何人都可以帮我弄清楚我在这里做错了吗?

3 个答案:

答案 0 :(得分:3)

我通过审查the result_of protocol documentation(与凤凰分开;我期待凤凰文档解释)找到了解决方案:

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 :(得分:1)

您使用了错误的占位符_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);
}

当然,如果需要,您可以检测到对类型。

完整代码 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();
}

答案 2 :(得分:0)

这不能解答您的问题,但它提供了基于现有实施的解决方法:(未经测试的代码)

#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)如果它是凤凰表达式,请使用enable_if丢弃TPair。 2)让operator()更加具体到std::pair,如下所示:

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