我有以下代码:
int MimeDocument::GetAttachmentId( std::string const& content_id )
{
using namespace boost::lambda;
using boost::lambda::_1;
using boost::bind;
int id = 0;
std::vector<std::string>::iterator it =
std::find_if( attachment_list_.begin(), attachment_list_.end(),
bind( &std::string::find, content_id, _1 ) != std::string::npos
);
if( it != attachment_list_.end() ) {
id = std::distance( attachment_list_.begin(), it );
}
return id;
}
在MSVC9 SP1上编译时导致大量C2780
编译器错误。以下是列表顶部的一些内容:
1>c:\code\work\cmake-mds\server\gmmserver\domino\server\interface\dimime.cpp(210) : error C2780: 'boost::_bi::bind_t<_bi::dm_result<MT::* ,A1>::type,boost::_mfi::dm<M,T>,_bi::list_av_1<A1>::type> boost::bind(M T::* ,A1)' : expects 2 arguments - 3 provided
1> c:\code\work\cmake-mds\build-vc9\third_party\boost\1.48.0\include\boost\bind\bind.hpp(1728) : see declaration of 'boost::bind'
1>c:\code\work\cmake-mds\server\gmmserver\domino\server\interface\dimime.cpp(210) : error C2780: 'boost::_bi::bind_t<Rt2,boost::_mfi::cmf8<R,T,B1,B2,B3,B4,B5,B6,B7,B8>,_bi::list_av_9<A1,A2,A3,A4,A5,A6,A7,A8,A9>::type> boost::bind(boost::type<T>,R (__thiscall T::* )(B1,B2,B3,B4,B5,B6,B7,B8) const,A1,A2,A3,A4,A5,A6,A7,A8,A9)' : expects 11 arguments - 3 provided
1> c:\code\work\cmake-mds\build-vc9\third_party\boost\1.48.0\include\boost\bind\bind_mf2_cc.hpp(223) : see declaration of 'boost::bind'
1>c:\code\work\cmake-mds\server\gmmserver\domino\server\interface\dimime.cpp(210) : error C2780: 'boost::_bi::bind_t<Rt2,boost::_mfi::mf8<R,T,B1,B2,B3,B4,B5,B6,B7,B8>,_bi::list_av_9<A1,A2,A3,A4,A5,A6,A7,A8,A9>::type> boost::bind(boost::type<T>,R (__thiscall T::* )(B1,B2,B3,B4,B5,B6,B7,B8),A1,A2,A3,A4,A5,A6,A7,A8,A9)' : expects 11 arguments - 3 provided
1> c:\code\work\cmake-mds\build-vc9\third_party\boost\1.48.0\include\boost\bind\bind_mf2_cc.hpp(212) : see declaration of 'boost::bind'
与boost相关的任何编译器错误实际上都是不可读的,对我没有帮助,所以我希望有人可以帮我弄清楚发生了什么。提前谢谢。
答案 0 :(得分:5)
std::string::find
有四个重载:
size_t find(const string& str, size_t pos = 0) const;
size_t find(const char* s, size_t pos, size_t n) const;
size_t find(const char* s, size_t pos = 0) const;
size_t find(char c, size_t pos = 0) const;
因此,必须通过指定地址所采用的特定重载函数来帮助编译器选择一个(解决歧义),例如:
boost::bind( static_cast<size_t(std::string::*)(const std::string&, size_t) const>(&std::string::find), content_id, _1, 0)
相当丑陋,不是吗?
请注意,std::string::find()
会在不成功的搜索中返回std::string::npos
(通常为size_t(-1)
)。然后它会将size_t(-1)
转换为bool(true)
并导致std::find_if()
返回其第一个参数,无论其余参数是什么。
std::string::find()
的结果需要与std::string::npos
进行比较。使用看似如下的boost::bind
:
// ...
std::vector<std::string>::iterator it = std::find_if(
attachment_list_.begin()
, attachment_list_.end()
, boost::bind(
std::not_equal_to<std::string::size_type>()
, std::string::npos
, boost::bind(
static_cast<size_t(std::string::*)(const std::string&, size_t) const>(&std::string::find)
, &content_id // pass by pointer, don't copy
, _1
, 0)
)
);
这看起来也不太可读。
使用boost::lambda::bind
:
#include <boost/lambda/bind.hpp>
#include <boost/lambda/lambda.hpp>
// ...
std::vector<std::string>::iterator it =
std::find_if(
attachment_list_.begin()
, attachment_list_.end()
, boost::lambda::constant(std::string::npos) != boost::lambda::bind(
static_cast<size_t(std::string::*)(const std::string&, size_t) const>(&std::string::find)
, &content_id // pass by pointer, don't copy
, boost::lambda::_1
, 0
)
);
使用C++11 lambda看起来最具可读性和优雅性:
std::vector<std::string>::iterator it = std::find_if(
attachment_list_.begin()
, attachment_list_.end()
, [&content_id](std::string const& i) { return std::string::npos != content_id.find(i); }
);
此外,我注意到,对于不成功的搜索返回的id
为0.它与第一个元素上的搜索成功时返回的值相同。换句话说,此函数的调用者将无法区分不成功的搜索和第一个(第0个)元素匹配时。
在这里使用普通循环进行搜索是最简单和便携的:
std::string* MimeDocument::GetAttachmentId(std::string const& content_id) {
for( std::vector<std::string>::iterator i(attachment_list_.begin()), j(attachment_list_.end())
; i != j
; ++i
) {
if(std::string::npos != content_id.find(*i))
return &*i;
}
return NULL;
}
使用此版本,调用者可以轻松判断成功搜索和不成功搜索,并在必要时找出匹配的索引:
MimeDocument doc;
// ... populate doc
if(std::string* found = doc.GetAttachmentId("1")) {
// the search was successful.
size_t found_index = found - &doc.attachment_list_.front();
}
所以,选择你的毒药......
答案 1 :(得分:2)
bind
的参数类型不以任何方式相互关联(正交模板类型),只有在 body 内,编译器才能确定{{1}的哪个重载是必要的。事实上,只允许编译器查看函数声明以确定要传入的内容,并且find
存在模糊的可能重载,并且编译器不能使用绑定参数类型来帮助找出哪一个使用
在这种情况下,我认为只编写一个5行仿函数来为你做嵌套字符串搜索可能会更简单。