Qualquer risco de mover elementos const_cast para fora de um std :: initializer_list?

Esta questão se baseia nessa@ Pergunta de FredOverflow.

ESCLARECIMENTO: initializer_list abordagem é necessária como oVC ++ 2012 tem um bug o impede a expansão encaminhada de argumentos com espaços para nome._MSC_VER <= 1700 tem o bug.

Eu escrevi uma função de modelo variadic que recolhe qualquer número de argumentos em um recipiente digitado. Eu uso o construtor do tipo para converter os argumentos variádicos em valores consumíveis. Por exemplo._variant_t :)

Eu preciso disso para o meuMySql Biblioteca C ++ ao enviar argumentos para instruções preparadas em um único golpe, enquantoMySqlVariant converte os dados de entrada paraMYSQL_BINDs. Como eu posso trabalhar comBLOBs, eu gostaria de evitar o copy-construct tanto quanto possível quando pudermove&& os grandes recipientes ao redor.

Eu fiz um teste simples e notei que oinitialize_list fazcopy-construct para os elementos armazenados e os destrói quando sai do escopo. Perfeito ... Então eu tentei mover os dados para fora doinitializer_list e, para minha surpresa, usoulvalues nãorvalues como eu esperava comstd::move.

Engraçado como isso acontece logo depoisIndo em 2013 nativo claramente me avisou quemove não se move, forward não avança...ser como a minha amiga - para ficar no fundo do pensamento.

Mas isso não me impediu :) eu decidi queconst_cast ainitializer_list valores e ainda movê-los para fora. Uma ordem de despejo precisa ser aplicada. E isso éminha implementação:

template <typename Output_t, typename ...Input_t>
inline Output_t& Compact(Output_t& aOutput, Input_t&& ...aInput){
    // should I do this? makes sense...
    if(!sizeof...(aInput)){
        return aOutput;
    }

    // I like typedefs as they shorten the code :)
    typedef Output_t::value_type Type_t;

    // can be either lvalues or rvalues in the initializer_list when it's populated.
    std::initializer_list<Type_t> vInput = { std::forward<Input_t>(aInput)... };

    // now move the initializer_list into the vector.
    aOutput.reserve(aOutput.size() + vInput.size());
    for(auto vIter(vInput.begin()), vEnd(vInput.end()); vIter != vEnd; ++vIter){
        // move (don't copy) out the lvalue or rvalue out of the initializer_list.
        // aOutput.emplace_back(std::move(const_cast<Type_t&>(*vIter))); // <- BAD!
        // the answer points out that the above is undefined so, use the below
        aOutput.emplace_back(*vIter); // <- THIS is STANDARD LEGAL (copy ctor)!
    }

    // done! :)
    return aOutput;
}

Usando isso é fácil:

// You need to pre-declare the container as you could use a vector or a list...
// as long as .emplace_back is on duty!
std::vector<MySqlVariant> vParams;
Compact(vParams, 1, 1.5, 1.6F, "string", L"wstring",
    std::move(aBlob), aSystemTime); // MySql params :)

Eu também fiz o upload de um teste completo na IDEone ^ que mostra como a memória de umstd::string move-se adequadamente com esta função.(Eu colaria tudo aqui, mas é um pouco longo ...)

Contanto que o_variant_t (ou qualquer objeto de embrulho final) tem os construtores certos, é ótimo. E se os dados puderem ser removidos, é ainda melhor. E funciona muito bem como eu testei e coisasstd::move na direção certa :)

Minhas perguntas são simples:

Estou fazendo isso corretamente?O fato de estar funcionando corretamente ou apenas um efeito colateral?E sestd::move não funciona por padrão eminitializer_listé o que estou fazendo aqui:ilegal, imoral, hacky ... ou simplesmente errado?

PS: Sou autodidataWindows Native C++ desenvolvedor, ignorante dos padrões.
^ minha desculpa se estou fazendo coisas realmente não-padrão aqui.

ATUALIZAR

Obrigado a todos, tenho a resposta e a solução(um curto e longo) agora.

E eu amo o lado C ++ 11 do SO. Muitas pessoas conhecedoras aqui ...

questionAnswers(3)

yourAnswerToTheQuestion