我有以下代码(在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
类型。
任何人都可以帮我弄清楚我在这里做错了吗?
答案 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;
}
...