2010-03-09 5 views
1

Il semble qu'un constructeur qui prend une référence non-const dans un istream ne puisse pas être construit avec une valeur temporaire dans C++.Référence d'istream temporaire non-const dans le constructeur (C++)

#include <iostream> 
#include <sstream> 

using namespace std; 

class Bar 
{ 
public: 
    explicit Bar(std::istream& is) {} 
}; 

int main() 
{ 
    istringstream stream1("bar1"); 
    Bar bar1(stream1); // OK on all platforms 

    // compile error on linux, Mac gcc; OK on Windows MSVC 
    Bar bar2(istringstream("bar2")); 

    return 0; 
} 

Cela compile bien avec MSVC, mais pas avec gcc. En utilisant gcc je reçois une erreur de compilation:

g++  test.cpp -o test 
test.cpp: In function ‘int main()’: 
test.cpp:18: error: no matching function for call to ‘Bar::Bar(std::istringstream)’ 
test.cpp:9: note: candidates are: Bar::Bar(std::istream&) 
test.cpp:7: note:     Bar::Bar(const Bar&) 

Y at-il quelque chose philosophiquement mal avec la deuxième voie (bar2) de construire un objet Bar? Il me semble plus agréable, et ne nécessite pas cette variable stream1 qui est seulement nécessaire pour un moment.

EDIT: En réponse au commentaire de Johannes Schaub, je voudrais donner un peu plus de contexte. Premièrement, ce n'est pas la première fois que je suis ennuyé par ce comportement du C++, donc je m'intéresse vraiment à la discussion philosophique de haut niveau sur ce sujet. Cela dit, dans ce cas particulier, j'ai une classe qui lit dans un fichier qui contient des données utilisées pour construire l'objet. J'aime aussi écrire des tests automatisés qui utilisent une chaîne à la place du fichier. Mais l'utilisation du fichier pour la construction est le principal cas d'utilisation. J'ai donc décidé de faire un constructeur qui prend un istream, donc je pourrais utiliser soit un fichier (stream), soit une chaîne (stream). C'est comme ça que je suis arrivé ici. Mes programmes de test construisent des objets directement à partir de chaînes, pour simuler la lecture de fichiers. Cela m'évite de créer des fichiers de données séparés pour chaque petit test.

+1

Vous pouvez passer 'istringstream (" bar2 "). Seekg (0)' comme solution de contournement. –

+0

Le comportement MSVC est une extension non standard qui génère un avertissement, et je pense que si vous activez le mode standard (/ Za), vous y trouverez également une erreur. –

+0

@Johannes Schaub: Très intelligent. Je suppose que toute méthode qui renvoie une référence à l'objet temporaire fonctionnerait ici. –

Répondre

3

Voici comment le C++ fonctionne actuellement: vous ne pouvez pas lier des références non-const à des objets temporaires. MSVC est non standard en permettant cela.

C++ 0x aura des références de valeur r et changera les choses autour d'un bit ici. Il ya diverses interprétations philosophiques que les gens ont essayé d'appliquer — pour les deux côtés de la question — mais je n'ai pas trouvé celui qui est tout à fait convaincant. Il semble plus de "vous avez juste à choisir un comportement et s'y tenir", ce qui explique à la fois les changements actuels de C++ et de 0x: le comportement choisi a changé.

+0

Voulez-vous dire que la construction "Bar bar2 (istringstream (" bar2 "));" travaillera dans la prochaine norme C++? Ce serait bien. –

+0

@Christopher, vous devrez surcharger le constructeur comme 'Bar explicite (std :: istream &) {..} Barre explicite (std :: istream &&) {..}'. Alors le premier saisira toutes les valeurs (principalement des variables), et le second saisira toutes les valeurs (principalement des temporaires comme les vôtres). –

+0

Presque, je dis que vous pouvez le faire fonctionner, comme le montre Johannes, mais pas que votre code actuel fonctionne magiquement dans 0x. –

1

Roger a raison ... c'est une politique générique de C++ que seules les références const peuvent lier aux temporaires. Je ne pense pas que les références rvalue vous aideraient, cependant, parce que dans le cas de passer un flux non-temporaire, vous voulez continuer à utiliser son état modifié. Plus précisément, pourquoi ne pas remplacer le constructeur par un extracteur friendistream &operator>>(istream &s, Bar &b)? Au prix d'ajouter un état non initialisé à l'objet, la syntaxe serait encore plus C++ - ish.

+0

+1 votre opérateur >> suggestion est une excellente idée. –

+0

Cet état non initialisé est l'une des raisons pour lesquelles je n'aime pas les iostreams. –

+0

Note associée: pourquoi 'int n; istringstream ("5") >> n; 'travail? – Potatoswatter

Questions connexes