#c #boost
#c #повышение
Вопрос:
Я пытаюсь использовать std::find_if на std::map, ища конкретный объект, который соответствует строке следующим образом:
class MyString
{
public:
MyString() {}
MyString(const std::stringamp; x) : m_x(x) {}
const std::stringamp; value() const
{
return m_x;
}
private:
std::string m_x;
};
std::map<int,MyString> squaresS;
std::map<int,MyString>::iterator iIt;
squaresS[1] = MyString("1");
squaresS[2] = MyString("4");
squaresS[3] = MyString("9");
const std::string sTarget = "4";
iIt = std::find_if(squaresS.begin(), squaresS.end(),
boost::bind(std::equal_to<std::string>(),
boost::bind(amp;MyString::value,
boost::bind(amp;std::map<int,MyString>::value_type::second, _1)),
sTarget));
if (iIt != squaresS.end())
std::cout << "Found " << iIt->second.value() << std::endl;
else
std::cout << "Not Found" << std::endl;
Результат выполнения этого кода не найден; Я ожидал, что будет выведен Found 4. Однако, если я делаю примерно то же самое, используя целые числа, тогда это работает, т.е. результат найден 4:
class MyInteger
{
public:
MyInteger() {}
MyInteger(int x) : m_x(x) {}
int value() const
{
return m_x;
}
private:
int m_x;
};
std::map<int,MyInteger> squaresI;
std::map<int,MyInteger>::iterator sIt;
squaresI[1] = MyInteger(1);
squaresI[2] = MyInteger(4);
squaresI[3] = MyInteger(9);
int iTarget = 4;
sIt = std::find_if(squaresI.begin(), squaresI.end(),
boost::bind(std::equal_to<int>(),
boost::bind(amp;MyInteger::value,
boost::bind(amp;std::map<int,MyInteger>::value_type::second, _1)),
iTarget));
if (sIt != squaresI.end())
std::cout << "Found " << sIt->second.value() << std::endl;
else
std::cout << "Not Found" << std::endl;
Я подозреваю, что это как-то связано с std::equal_to, но я не уверен, как это исправить.
Комментарии:
1. Не относящийся к делу комментарий: иногда я просто поражаюсь тому, насколько сильно можно опьянеть от такого ужасного нечитаемого синтаксиса один маленький шаг за другим. Что-то вроде истории с кипящей лягушкой о boost, вероятно.
2. @6502, я слышу тебя … простой функтор был бы значительно более понятным, чем эта магия привязки…
<sigh/>
3. На самом деле ваш приведенный выше код для
MyString
workds для меня: ideone.com/DZ0lx , вам все равно следует добавить соответствующий конструктор копирования!4. @Nim: Согласен. C 0x практически здесь, и есть очень мало причин избегать новых функций в новом коде. Конечно, я немного боюсь того кода, который люди будут писать с помощью
algorithm
и лямбдовых выражений, когдаfor
было бы достаточно: подумайте о том, что jQuery сделал с разработкой JavaScript, и вы поймете, что я имею в виду.5. Ваш код для myString также работает для меня с gcc-4.2.1
Ответ №1:
Вот что вы могли бы сделать:
class MyString
{
public:
MyString() {}
MyString(const std::stringamp; x) : m_x(x) {}
const std::stringamp; value() const
{
return m_x;
}
private:
std::string m_x;
};
class mystringmatch
{
MyString _target;
public:
mystringmatch(const MyStringamp; target):_target(target)
{
}
bool operator()(const std::pair<int, MyString>amp; src) const
{
return src.second.value() == _target.value();
}
};
int _tmain(int argc, _TCHAR* argv[])
{
std::map<int,MyString> squaresS;
std::map<int,MyString>::iterator iIt;
squaresS[1] = MyString("1");
squaresS[2] = MyString("4");
squaresS[3] = MyString("9");
const std::string sTarget = "4";
iIt = std::find_if(squaresS.begin(), squaresS.end(), mystringmatch(sTarget));
if (iIt != squaresS.end())
std::cout << "Found " << iIt->second.value() << std::endl;
else
std::cout << "Not Found" << std::endl;
return 0;
}
На мой взгляд, такой код заставляет людей переходить с C на другие языки. Это почти невозможно прочитать.
sIt = std::find_if(squaresI.begin(), squaresI.end(),
boost::bind(std::equal_to<int>(),
boost::bind(amp;MyInteger::value,
boost::bind(amp;std::map<int,MyInteger>::value_type::second, _1)),
iTarget));
Ответ №2:
Как отметили другие, ваш код уже работает для меня (VC 2010 SP1). Тем не менее, есть тривиальное изменение, которое можно внести, чтобы уменьшить количество вложенных bind
типов — возвращаемые типы boost::bind
(в отличие от возвращаемых std::bind
) имеют все реляционные и логические операторы, включая перегруженные operator==
, устраняя (или, по крайней мере, смягчая) необходимость в адаптерах, подобных std::equal_to<>
. Использование этого упрощает ваш код до чего-то вроде:
typedef std::map<int, MyString> squares_t;
squares_t::const_iterator iIt = std::find_if(
squaresS.begin(),
squaresS.end(),
boost::bind(
amp;MyString::value,
boost::bind(amp;squares_t::value_type::second, ::_1)
) == sTarget
);
Посмотрите на повышение.Свяжите документы для получения дополнительной информации.
Комментарии:
1. Спасибо, я использовал VC 2005 для компиляции, так что, думаю, пришло время для обновления! Мне нравится, как вы используете operator () ==.