std::foreach с boost::bind

Что с этим не так:

template <typename T>
std::list<T> & operator+=(std::list<T> & first, std::list<T> const& second)
{
    std::for_each(second.begin(), second.end(), boost::bind(&std::list<T>::push_back, first, _1));

    return first;
}

Компилируется нормально, но не работает.


person Heptic    schedule 21.05.2011    source источник
comment
что значит не работает точно?   -  person Mat    schedule 21.05.2011
comment
Это не отвечает на ваш вопрос, но если ваш код действительно надуманный (в отличие от примера, урезанного для вопроса, я имею в виду), что не так с std::copy с std::back_inserter?   -  person Lightness Races in Orbit    schedule 21.05.2011
comment
Чтобы дополнить Томалака, стандартная идиома для выполнения этого в С++: std::copy(second.begin(), second.end(), std::back_inserter(first));   -  person Boaz Yaniv    schedule 21.05.2011


Ответы (2)


Вам нужно использовать boost::ref для передачи аргумента/объекта по ссылке, иначе привязка создает внутреннюю копию.

std::for_each(
    second.begin(), second.end(),
    boost::bind(&std::list<T>::push_back, boost::ref(first), _1)
);
person Cat Plus Plus    schedule 21.05.2011
comment
Конечно, это не меняет того факта, что &std::list<T>::push_back имеет неопределенное поведение, поэтому он по-прежнему может компилироваться или не компилироваться (и фактически гарантируется нет для любого компилятора с поддержкой ссылок rvalue)... - person ildjarn; 21.05.2011
comment
Спасибо Кэт, это работает. @ildjarn, не могли бы вы дать ссылку на дополнительную информацию о том, почему &std::list‹T›::push_back может иметь неопределенное поведение? - person Heptic; 21.05.2011
comment
comment
@Heptic: Тем не менее, лучший способ сделать то, что вы хотите, - это back_inserter, рассматривайте этот ответ скорее как общее решение того, почему моя привязка работает с другим объектом, чем должна, даже если у меня есть ссылки. - person Cat Plus Plus; 21.05.2011

Обратите внимание, что, хотя решение Cat Plus Plus будет работать для вас, рекомендуемый способ делать такие вещи в C++03 (до появления лямбда-выражений в готовящейся к выпуску стандартной версии) заключается в использовании алгоритмов и функторов стандартной библиотеки. К сожалению, в некоторых случаях они сами становятся довольно запутанными, но в этом случае я думаю, что они дают более понятный код:

std::copy(second.begin(), second.end(), std::back_inserter(first));
person Boaz Yaniv    schedule 21.05.2011
comment
Обратите внимание, что хотя решение Cat Plus Plus вам подойдет Абсолютно нет; этот код отказался бы компилироваться на любом компиляторе, выпущенном за последний год или два. - person ildjarn; 21.05.2011
comment
@BoazYaniv: пока он не обновит свой компилятор. ;-] - person ildjarn; 21.05.2011
comment
# включая алгоритм и итератор, а затем используя std::copy() и back_inserter() здесь слишком много работы без причины, imo. И действительно, когда стандарт предлагает функцию-член, вы должны использовать ее, а не общий алгоритм. - person wilhelmtell; 21.05.2011
comment
@wilhelmtell: хотя я согласен с тем, что list<>::insert здесь более уместен, какой реальный код C++ еще не включает algorithm и iterator? - person ildjarn; 21.05.2011
comment
@wilhelmtell: в этом случае со списком «T» я соглашусь, что использование вставки () еще более читабельно, но std::copy полезно во многих случаях, когда вы не хотите фиксироваться на одном контейнере. - person Boaz Yaniv; 21.05.2011