在std :: string :: find上使用boost :: bind无法编译

voi*_*ter 3 c++ boost stl compiler-errors boost-bind

我有以下代码:

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;
}
Run Code Online (Sandbox Code Playgroud)

在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'
Run Code Online (Sandbox Code Playgroud)

任何与boost相关的编译器错误实际上都是不可读的,对我没有帮助,所以我希望有人可以帮我弄清楚发生了什么.提前致谢.

Max*_*kin 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;
Run Code Online (Sandbox Code Playgroud)

因此,必须通过指定地址所采用的特定重载函数来帮助编译器选择一个(解决歧义),例如:

boost::bind( static_cast<size_t(std::string::*)(const std::string&, size_t) const>(&std::string::find), content_id, _1, 0)
Run Code Online (Sandbox Code Playgroud)

相当难看,不是吗?

注意,在不成功的搜索中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)
            )
    );
Run Code Online (Sandbox Code Playgroud)

哪个看起来也不太可读.

它可能有点可读性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
            )
    );
Run Code Online (Sandbox Code Playgroud)

使用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); }
    );
Run Code Online (Sandbox Code Playgroud)

此外,我注意到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;
}
Run Code Online (Sandbox Code Playgroud)

使用此版本,调用者可以轻松地在成功和不成功的搜索之间进行判断,并在必要时找出匹配的索引:

MimeDocument doc;
// ... populate doc
if(std::string* found = doc.GetAttachmentId("1")) {
    // the search was successful.
    size_t found_index = found - &doc.attachment_list_.front();
}
Run Code Online (Sandbox Code Playgroud)

所以,选择你的毒药......