Eu tenho esta função que usa std::partition para dividir um contêiner em dois com base em um predicado.
template<class Container, class Predicate>
void split_partition(Container& src, Container& dest, Predicate p)
{
auto ends = std::partition_copy(
std::make_move_iterator( src.begin() ), std::make_move_iterator( src.end() ),
src.begin(), std::back_inserter(dest), p
);
src.erase(ends.first, src.end());
}
Eu tentei ligar com
split_partition(a, b, [](auto& t) {return t.i > 4; });
mas nem compilou, agora se usar const funciona.
split_partition(a, b, [](const auto& t) {return t.i > 4; });
Por que é que?
Editar:
std::vector<Thing> a = { {0, "foo"}, {1, "bar"}, {5, "what"}, {8, "yo"}, {2, ""} };
std::vector<Thing> b;
Você está pagando
std::partition
com um range movido:Isso significa que o lambda que você possui será invocado com algum
Object&&
ouconst Object&&
.const auto&
pode vincular-se a ele em ambos os casos.const auto&
é universal no sentido de que pode ser vinculado a qualquer categoria de valor (lvalue, xvalue, prvalue).Por exemplo:
Este código é compilado para
Isso significa que nenhum construtor
S
foi chamado,const&
simplesmente se liga a qualquer coisa. Como você está usandostd::move_iterator
(o que é inútil para fins de comparação), seu caso ér1
orr3
.auto&
não é tão poderoso: uma referência não-const lvalue não pode ser vinculada a um const xvalue. Isso seriar3
, e esse é o caso que você está enfrentando.- [dcl.init.ref] p5.2
Solução
Basta aceitar
const auto&
em seu lambda. É mais correto, pois você está apenas comparando elementos sem modificá-los.