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

时间:2012-03-15 16:50:22

标签: 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;
}

在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相关的任何编译器错误实际上都是不可读的,对我没有帮助,所以我希望有人可以帮我弄清楚发生了什么。提前谢谢。

2 个答案:

答案 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行仿函数来为你做嵌套字符串搜索可能会更简单。