87 votes

C++11 make_pair spécifié avec des paramètres de modèle ne compile pas

Je viens de jouer avec g++ 4.7 (l'un des derniers instantanés) avec -std=c++11 activé. J'ai essayé de compiler une partie de mon code de base et un cas d'échec un peu me confond.

Je vous serais reconnaissant si quelqu'un peut expliquer ce qui se passe.

Voici le code

#include <utility>
#include <iostream>
#include <vector>
#include <string>

int main ( )
{
    std::string s = "abc";

    // 1 ok
    std::pair < std::string, int > a = std::make_pair ( s, 7 );

    // 2 error on the next line
    std::pair < std::string, int > b = std::make_pair < std::string, int > ( s, 7 );

    // 3 ok
    std::pair < std::string, int > d = std::pair < std::string, int > ( s, 7 );

    return 0;
}

Je comprends que make_pair est censé être utilisé comme (1) cas (si j'ai spécifier les types, alors je pourrais aussi bien utiliser (3)), Mais je ne comprends pas pourquoi cela ne fonctionne pas dans ce cas.

L'erreur exacte est:

test.cpp: In function ‘int main()':
test.cpp:11:83: error: no matching function for call to ‘make_pair(std::string&, int)'
test.cpp:11:83: note: candidate is:
In file included from /gcc4.7/usr/local/lib/gcc/i686-pc-linux-gnu/4.7.0/../../../../include/c++/4.7.0/utility:72:0,
             from test.cpp:1:
/gcc4.7/usr/local/lib/gcc/i686-pc-linux-gnu/4.7.0/../../../../include/c++/4.7.0/bits/stl_pair.h:274:5: note: template<class _T1, class _T2> constexpr std::pair<typename std::__decay_and_strip<_T1>::__type, typename std::__decay_and_strip<_T2>::__type> std::make_pair(_T1&&, _T2&&)
/gcc4.7/usr/local/lib/gcc/i686-pc-linux-gnu/4.7.0/../../../../include/c++/4.7.0/bits/stl_pair.h:274:5: note:   template argument deduction/substitution failed:
test.cpp:11:83: note:   cannot convert ‘s' (type ‘std::string {aka std::basic_string<char>}') to type ‘std::basic_string<char>&&'

Encore une fois, la question ici est juste de "what's going on?" Je sais que je peux résoudre le problème en supprimant le modèle de cahier des charges, mais je veux juste savoir ce qui ne fonctionne pas ici sous les couvertures. Merci à l'avance.

EDIT:

  • g++ 4.4 compile ce code avec pas de problèmes.
  • Retrait -std=c++11 est également compile avec code avec pas de problèmes.

142voto

James McNellis Points 193607

Ce n'est pas la façon dont std::make_pair est destiné à être utilisé; vous n'êtes pas censé pour spécifier explicitement les arguments de modèle.

Le C++11 std::make_pair prend deux arguments de type T&& et U&&T et U sont modèle de paramètres de type. Effectivement, ça ressemble à ça (en ignorant le type de retour):

template <typename T, typename U>
[return type] make_pair(T&& argT, U&& argU);

Lorsque vous appelez std::make_pair et de spécifier explicitement le type de modèle arguments, aucun argument déduction a lieu. Au lieu de cela, les arguments de type sont remplacés directement dans le modèle de déclaration, rendement:

[return type] make_pair(std::string&& argT, int&& argU);

Notez que ces deux types de paramètres sont des références rvalue. Ainsi, ils ne peuvent se lier à des rvalues. Ce n'est pas un problème pour le deuxième argument que vous passez, 7, parce que c'est une rvalue expression. s, cependant, est une lvalue expression (il n'est pas temporaire et il n'est pas déplacé). Cela signifie que le modèle de fonction n'est pas un match pour vos arguments, c'est pourquoi vous obtenez l'erreur.

Alors, pourquoi est-il travail quand vous n'avez pas de spécifier de manière explicite ce qu' T et U sont dans le modèle de la liste d'arguments? En bref, rvalue des paramètres de référence sont spéciaux dans les modèles. En partie à cause de la langue fonctionnalité appelée référence de l'effondrement, une référence rvalue paramètre de type A&&A est un modèle de paramètre de type, peut se lier à n'importe quel type d' A.

Il n'a pas d'importance si l' A est une lvalue, une rvalue, const-qualifiés, volatile-qualifiés ou non qualifiés, A&& peut se lier à un objet (encore une fois, si et seulement si A est elle-même un paramètre du modèle).

Dans votre exemple, nous faisons l'appel:

make_pair(s, 7)

Ici, s est une lvalue de type std::string et 7 est une rvalue de type int. Puisque vous ne spécifiez pas les arguments de modèle pour le modèle de fonction, l'argument de modèle déduction est effectuée pour déterminer les arguments.

Pour lier s, une lvalue, T&&, le compilateur déduit T être std::string&, ce qui donne un argument de type std::string& &&. Il n'y a pas de références à des références, mais, si ce "double référence" s'effondre à devenir std::string&. s est un match.

Il est simple de lier 7 de U&&: le compilateur peut en déduire U être int, ce qui donne un paramètre de type int&&, qui se lie avec succès à l' 7 parce que c'est une rvalue.

Il y a beaucoup de subtilités avec ces nouvelles fonctionnalités de la langue, mais si vous suivez une règle simple, il est assez facile:

Si un argument de modèle peuvent être déduites à partir des arguments de la fonction, qu'elle soit déduite. Ne pas prévoir explicitement l'argument, sauf si vous devez absolument.

Laisser le compilateur faire le travail dur, et de 99,9% du temps, ça va être exactement ce que vous voulez de toute façon. Quand ce n'est pas ce que vous vouliez, vous devriez obtenir une erreur de compilation qui est facile à identifier et à corriger.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X