No C ++ 11, você pode fazer quase inteiramente sem make_pair. Veja minha resposta .
PlagueHammer
2
No C ++ 17, std::make_pairé redundante. Há uma resposta abaixo que detalha isso.
Drew Dormann
Respostas:
165
A diferença é que, com std::pairvocê, é necessário especificar os tipos de ambos os elementos, ao passo std::make_pairque criará um par com o tipo dos elementos que são passados para ele, sem a necessidade de informar. É o que eu pude reunir de vários documentos.
"O C ++ 17 torna essa sintaxe possível e, portanto, torna o par redundante." - Por que std::make_pairnão foi preterido no C ++ 17?
andreee
@andreee Não tenho certeza, o possível motivo é que ele não cria problemas, portanto não há necessidade de quebrar o código antigo? Mas eu não estou familiarizado com o raciocínio do comitê C ++, faça ping se encontrar alguma coisa.
Ciro Santilli #
1
Uma coisa útil que me deparei é que a capacidade de especificar os tipos com std :: make_pair <T1, T2> (o1, o2) impede que o usuário cometa o erro de passar os tipos o1 ou o2 que não podem ser implicitamente convertido para T1 ou T2. Por exemplo, passando um número negativo para um int não assinado. -Wsign-conversion -Werror não detectará esse erro com o construtor std :: pair no c ++ 11, mas detectará o erro se std :: make_pair for usado.
conchoecia
make_pairdesembrulha invólucros de referência, por isso é diferente do CTAD.
LF
26
Não há diferença entre usar make_paire chamar explicitamente o pairconstrutor com argumentos de tipo especificado. std::make_pairé mais conveniente quando os tipos são detalhados porque um método de modelo possui dedução de tipo com base em seus parâmetros fornecidos. Por exemplo,
Vale a pena notar que esse é um idioma comum na programação de modelos C ++. É conhecido como o idioma do Gerador de Objetos, você pode encontrar mais informações e um bom exemplo aqui .
Editar Como alguém sugeriu nos comentários (desde que removido), a seguir é um extrato ligeiramente modificado do link, caso ele se quebre.
Um gerador de objetos permite a criação de objetos sem especificar explicitamente seus tipos. Ele se baseia em uma propriedade útil dos modelos de função que os modelos de classe não possuem: Os parâmetros de tipo de um modelo de função são deduzidos automaticamente de seus parâmetros reais. std::make_pairé um exemplo simples que retorna uma instância do std::pairmodelo, dependendo dos parâmetros reais da std::make_pairfunção.
make_pair cria uma cópia extra sobre o construtor direto. Eu sempre digitava meus pares para fornecer uma sintaxe simples.
Isso mostra a diferença (exemplo de Rampal Chaudhary):
Tenho certeza de que a cópia extra será elidida em todos os casos, se as configurações de otimização do compilador forem altas o suficiente.
Björn Pollex
1
Por que você gostaria de confiar nas otimizações do compilador para correção?
Sjbx 02/12/16
Eu obtenho os mesmos resultados com as duas versões e std::moveapenas dentro inserte / ou em torno do que seria uma referência sample. Somente quando mudo std::map<int,Sample>para std::map<int,Sample const&>isso reduzo o número de objetos construídos e somente quando excluo o construtor de cópias é que elimino todas as cópias (obviamente). Depois de fazer essas duas alterações, meu resultado inclui uma chamada para o construtor padrão e duas chamadas para o destruidor para o mesmo objeto. Eu acho que devo estar faltando alguma coisa. (g ++ 5.4.1, c ++ 11)
João P
FWIW Concordo que a otimização e a correção devem ser completamente independentes, pois esse é exatamente o tipo de código que você escreve como verificação de integridade após diferentes níveis de otimização produzirem resultados inconsistentes. Em geral, eu recomendaria, em emplacevez de, insertse você está construindo um valor para inserir imediatamente (e não deseja instâncias extras). Não é minha área de especialização, se posso dizer que tenho uma, mas copiar / mover a semântica introduzida pelo C ++ 11 me ajudou muito.
John P
Acredito que estou encontrando exatamente o mesmo problema e, depois de depurar a noite inteira, finalmente cheguei aqui.
lllllllllllll
1
a partir do c ++ 11, basta usar a inicialização uniforme para pares. Então, em vez de:
{1, 2}pode ser usado para inicializar um par, mas não confirma para o par de tipos. Ou seja, ao usar auto você tem de se comprometer com um tipo no RHS: auto p = std::pair{"Tokyo"s, 9.00};.
std::make_pair
é redundante. Há uma resposta abaixo que detalha isso.Respostas:
A diferença é que, com
std::pair
você, é necessário especificar os tipos de ambos os elementos, ao passostd::make_pair
que criará um par com o tipo dos elementos que são passados para ele, sem a necessidade de informar. É o que eu pude reunir de vários documentos.Veja este exemplo em http://www.cplusplus.com/reference/std/utility/make_pair/
Além do bônus implícito de conversão, se você não usasse make_pair, teria que fazer
toda vez que você atribuiu a um, o que seria irritante ao longo do tempo ...
fonte
std::make_pair
. Aparentemente, é apenas por conveniência.one = {10, 20}
hoje em dia, mas não tenho um compilador C ++ 11 à mão para verificá-lo.make_pair
funciona com tipos sem nome, incluindo estruturas, uniões, lambdas e outros doodads.Como o @MSalters respondeu acima, agora você pode usar chaves para fazer isso no C ++ 11 (verifique isso apenas com um compilador C ++ 11):
fonte
Argumentos de modelo de classe não puderam ser deduzidos do construtor antes do C ++ 17
Antes do C ++ 17, você não podia escrever algo como:
pois isso inferiria tipos de modelo a partir dos argumentos do construtor.
O C ++ 17 torna essa sintaxe possível e, portanto,
make_pair
redundante.Antes do C ++ 17,
std::make_pair
nos permitia escrever um código menos detalhado:em vez do mais detalhado:
que repete os tipos e pode ser muito longo.
A inferência de tipo funciona nesse caso anterior ao C ++ 17 porque
make_pair
não é um construtor.make_pair
é essencialmente equivalente a:O mesmo conceito se aplica a
inserter
vsinsert_iterator
.Veja também:
Exemplo mínimo
Para tornar as coisas mais concretas, podemos observar o problema minimamente com:
main.cpp
então:
compila alegremente, mas:
falha com:
e requer, em vez disso, trabalhar:
ou o ajudante:
que usa uma função regular em vez de um construtor.
Diferença para `std :: reference_wrapper
Este comentário menciona que
std::make_pair
desembrulhastd::reference_wrapper
enquanto o construtor não, então essa é uma diferença. Exemplo TODO.Testado com o GCC 8.1.0, Ubuntu 16.04 .
fonte
std::make_pair
não foi preterido no C ++ 17?make_pair
desembrulha invólucros de referência, por isso é diferente do CTAD.Não há diferença entre usar
make_pair
e chamar explicitamente opair
construtor com argumentos de tipo especificado.std::make_pair
é mais conveniente quando os tipos são detalhados porque um método de modelo possui dedução de tipo com base em seus parâmetros fornecidos. Por exemplo,fonte
Vale a pena notar que esse é um idioma comum na programação de modelos C ++. É conhecido como o idioma do Gerador de Objetos, você pode encontrar mais informações e um bom exemplo aqui .
Editar Como alguém sugeriu nos comentários (desde que removido), a seguir é um extrato ligeiramente modificado do link, caso ele se quebre.
Um gerador de objetos permite a criação de objetos sem especificar explicitamente seus tipos. Ele se baseia em uma propriedade útil dos modelos de função que os modelos de classe não possuem: Os parâmetros de tipo de um modelo de função são deduzidos automaticamente de seus parâmetros reais.
std::make_pair
é um exemplo simples que retorna uma instância dostd::pair
modelo, dependendo dos parâmetros reais dastd::make_pair
função.fonte
&&
desde C ++ 11.make_pair cria uma cópia extra sobre o construtor direto. Eu sempre digitava meus pares para fornecer uma sintaxe simples.
Isso mostra a diferença (exemplo de Rampal Chaudhary):
fonte
std::move
apenas dentroinsert
e / ou em torno do que seria uma referênciasample
. Somente quando mudostd::map<int,Sample>
parastd::map<int,Sample const&>
isso reduzo o número de objetos construídos e somente quando excluo o construtor de cópias é que elimino todas as cópias (obviamente). Depois de fazer essas duas alterações, meu resultado inclui uma chamada para o construtor padrão e duas chamadas para o destruidor para o mesmo objeto. Eu acho que devo estar faltando alguma coisa. (g ++ 5.4.1, c ++ 11)emplace
vez de,insert
se você está construindo um valor para inserir imediatamente (e não deseja instâncias extras). Não é minha área de especialização, se posso dizer que tenho uma, mas copiar / mover a semântica introduzida pelo C ++ 11 me ajudou muito.a partir do c ++ 11, basta usar a inicialização uniforme para pares. Então, em vez de:
ou
Apenas use
fonte
{1, 2}
pode ser usado para inicializar um par, mas não confirma para o par de tipos. Ou seja, ao usar auto você tem de se comprometer com um tipo no RHS:auto p = std::pair{"Tokyo"s, 9.00};
.