Существует четыре перегрузки 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 лямбда :
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();
}
Итак, подбери свой яд ...