2

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

谁能帮我弄清楚我在这里做错了什么?

4

3 回答 3

3

我通过查看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;
}

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

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

using namespace boost::phoenix::placeholders;
namespace phx = boost::phoenix;
于 2014-03-23T19:59:10.593 回答
1

您使用了错误的 placeholder _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();
}
于 2014-03-23T19:53:19.150 回答
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丢弃。TPair2)让你operator()更具体std::pair,像这样:

   ...
   template<class T1, T2> // change `result` accordingly.
   T1& operator() (std::pair<T1, T2>& pair)
   {
      return pair.first;
   }
   ...
于 2014-03-23T19:32:25.427 回答