web-dev-qa-db-fra.com

std :: vector: ne peut pas lier 'std :: ostream {aka std :: basic_ostream <char>}' lvalue à 'std :: basic_ostream <char> &&'

J'ai rencontré un message d'erreur déroutant lorsque j'essayais de faire quelque chose d'aussi simple que

std::cout << std::vector<int>{1,2,3};

qui dit

 cannot bind 'std::ostream {aka std::basic_ostream<char>}' lvalue to 'std::basic_ostream<char>&&'
 int main() {  std::cout << std::vector<int>{1,2,3}; }

(testé avec gcc-4.8.1 avec -std = c ++ 11)

SO a des questions similaires comme l'opérateur de surcharge <<: ne peut pas lier la valeur à ‘std :: basic_ostream <char> &&’ , qui concerne une classe définie par l'utilisateur avec des classes imbriquées. Il y a aussi un travail autour de la réponse acceptée à cette question.

Mais je ne sais pas si cela s'applique à std::vector. Quelqu'un peut-il expliquer pourquoi cette erreur arrive à std::vector, et comment l'interpréter?

Merci

21
tinlyx

Les messages d'erreur liés aux modèles peuvent parfois prêter à confusion. Le problème est que la bibliothèque standard ne définit pas une surcharge de operator << pour insérer std::vector (ou tout autre conteneur, d'ailleurs) dans un std::ostream. Le compilateur ne parvient donc pas à trouver une surcharge appropriée pour operator <<, et signale cet échec du mieux qu'il est possible (ce qui n'est malheureusement pas trop bon/lisible dans votre cas).

Si vous souhaitez diffuser un conteneur entier, vous pouvez utiliser std::ostream_iterator pour cela:

auto v = std::vector<int>{1, 2, 3};
std::copy(begin(v), end(v), std::ostream_iterator<int>(std::cout, " "));

Quant à savoir pourquoi vous obtenez précisément cette erreur cryptique, cela aide à analyser le message d'erreur complet:

prog.cpp: In function ‘int main()’:
prog.cpp:13:37: error: cannot bind ‘std::ostream {aka std::basic_ostream<char>}’ lvalue to ‘std::basic_ostream<char>&&’
  std::cout << std::vector<int>{1,2,3};
                                     ^
In file included from /usr/include/c++/4.8/iostream:39:0,
                 from prog.cpp:3:
/usr/include/c++/4.8/ostream:602:5: error:   initializing argument 1 of ‘std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char; _Traits = std::char_traits<char>; _Tp = std::vector<int>]’
     operator<<(basic_ostream<_CharT, _Traits>&& __os, const _Tp& __x)
     ^

Il y a apparemment une surcharge de modèle de operator<< qui prend un argument lhs de type std::ostream&& et un argument rhs de type modèle; il existe pour permettre l'insertion dans des flux temporaires. Puisqu'il s'agit d'un modèle, il devient la meilleure correspondance pour l'expression dans votre code. Pourtant, std::cout est une valeur l, elle ne peut donc pas se lier à std::ostream&&. D'où l'erreur.

22
Angew

C'est un problème connu avec gcc, J'ai déposé une demande d'amélioration à ce sujet.

Le "seul" problème est que la chose que vous essayez d'imprimer sur la console n'a pas de operator<<. Malheureusement, le message d'erreur n'est pas très utile. :(

Soit dit en passant, la question n'a rien à voir avec les références vector ou l-value et r-value. Un exemple minimal:

#include <iostream>

struct A { };

int main() {
    A a;
    std::cout << a;
}

Voir la discussion à la demande d'amélioration pour les détails sanglants. En bref, les développeurs de gcc avaient déjà essayé d'améliorer le message d'erreur mais cela s'est avéré notoirement difficile.

Pour ce que ça vaut, le message d'erreur de clang avec libc ++ est plus clair à mon avis :

clang++ -std=c++11 -stdlib=libc++ -lc++abi main.cpp && ./a.out
main.cpp:7:15: error: invalid operands to binary expression ('ostream' (aka 'basic_ostream<char>') and 'A')
    std::cout << a;
    ~~~~~~~~~ ^  ~

Ici, la première ligne indique clairement quel est le problème.

9
Ali