Question

Je veux écrire une fonction qui transmet quelque chose à un ostream qui est passé dans, et retourner le flux, comme ceci:

std::ostream& MyPrint(int val, std::ostream* out) {
  *out << val;
  return *out;
}

int main(int argc, char** argv){
    std::cout << "Value: " << MyPrint(12, &std::cout) << std::endl;
    return 0;
}

Il serait commode d'imprimer la valeur comme celui-ci et intégrer l'appel de fonction dans la chaîne de l'opérateur de sortie, comme je l'ai fait dans main().

Il ne fonctionne pas, cependant, et imprime ceci:

$ ./a.out
12Value: 0x6013a8

La sortie souhaitée serait la suivante:

Value: 12

Comment puis-je résoudre ce problème? Dois-je définir un operator<< à la place?

Mise à jour:. ce que la sortie Clarifiée souhaitée serait

MAJ2: Certaines personnes ne comprennent pas pourquoi j'imprimer un numéro comme ça, en utilisant une fonction au lieu d'imprimer directement. Ceci est un exemple simplifié, et en réalité, la fonction imprime un objet complexe plutôt que d'un int.

Était-ce utile?

La solution

Vous ne pouvez pas fixer la fonction. Rien dans la spécification nécessite un compilateur pour évaluer un appel de fonction dans une expression dans un ordre particulier en ce qui concerne certains opérateur indépendant dans la même expression. Donc, sans changer le code d'appel, vous ne pouvez pas évaluer MyPrint() après std::cout << "Value: "

de gauche à droite est obligatoire pour les expressions constituées de plusieurs consécutifs << opérateurs, ce qui va fonctionner. Le point de l'opérateur << retour du courant est que, lorsque les opérateurs sont enchaînés, le LHS de chacun est alimenté par l'évaluation de l'opérateur à sa gauche.

Vous ne pouvez pas obtenir la même chose avec les appels de fonction gratuits parce qu'ils ne disposent pas d'un LHS. MyPrint() retourne un objet égal à std::cout, et le fait std::cout << "Value: ", donc vous faites efficacement std::cout << std::cout, qui est l'impression que valeur hexadécimale.

Etant donné que la sortie souhaitée est la suivante:

Value: 12

la « bonne » chose à faire est en effet de passer outre l'opérateur <<. Cela signifie souvent que vous devez soit faire un ami, ou faire ceci:

class WhateverItIsYouReallyWantToPrint {
    public:
    void print(ostream &out) const {
        // do whatever
    }
};

ostream &operator<<(ostream &out, const WhateverItIsYouReallyWantToPrint &obj) {
    obj.print(out);
}

Si operator<< primordiale pour votre classe ne convient pas, par exemple parce qu'il ya plusieurs formats que vous voudrez peut-être imprimer, et que vous voulez écrire une fonction différente pour chacun d'eux, vous devriez alors renoncer à l'idée de enchaînement de l'opérateur et il suffit d'appeler la fonction, ou écrire autre plusieurs classes qui prennent votre objet en tant que paramètre constructeur, chacun avec différents opérateurs surcharges.

Autres conseils

Vous voulez faire MyPrint une classe avec l'opérateur ami <<:

class MyPrint
{
public:
    MyPrint(int val) : val_(val) {}
    friend std::ostream& operator<<(std::ostream& os, const MyPrint& mp) 
    {
        os << mp.val_;
        return os;
    }
private:
    int val_;
};

int main(int argc, char** argv)
{
    std::cout << "Value: " << MyPrint(12) << std::endl;
    return 0;
}

Cette méthode vous oblige à insérer l'objet MyPrint dans le flux de votre choix. Si vous avez vraiment besoin de la capacité de changer le cours d'eau est actif, vous pouvez faire ceci:

class MyPrint
{
public:
    MyPrint(int val, std::ostream& os) : val_(val), os_(os) {}
    friend std::ostream& operator<<(std::ostream& dummy, const MyPrint& mp) 
    {
        mp.os_ << mp.val_;
        return os_;
    }
private:
    int val_;
    std::ostream& os_
};

int main(int argc, char** argv)
{
    std::cout << "Value: " << MyPrint(12, std::cout) << std::endl;
    return 0;
}

Vous avez deux options. La première, en utilisant ce que vous avez déjà est:

std::cout << "Value: ";
MyPrint(12, &std::cout);
std::cout << std::endl;

L'autre, qui est plus C ++ - comme, est de remplacer MyPrint() avec le std::ostream& operator<< approprié. Il y a déjà un pour int, donc je vais faire un juste un peu plus complexe:

#include <iostream>

struct X {
    int y;
};

// I'm not bothering passing X as a reference, because it's a
// small object
std::ostream& operator<<(std::ostream& os, const X x)
{
    return os << x.y;
}

int main()
{
    X x;
    x.y = 5;
    std::cout << x << std::endl;
}

Il n'y a pas moyen de faire ce que vous vous attendez là à cause de l'ordre les fonctions sont évaluées.

Y at-il une raison particulière que vous devez écrire directement au ostream comme ça? Dans le cas contraire, viennent MyPrint retourner une chaîne. Si vous souhaitez utiliser un flux à l'intérieur MyPrint pour générer la sortie, il suffit d'utiliser un strstream et retourner le résultat.

Tout d'abord, il n'y a aucune raison de ne pas passer dans le ostream par référence plutôt que par un pointeur:

std::ostream& MyPrint(int val, std::ostream& out) {
  out << val;
  return out;
}

Si vous ne voulez vraiment pas utiliser std::ostream& operator<<(std::ostream& os, TYPE), vous pouvez faire ceci:

int main(int argc, char** argv){
    std::cout << "Value: ";
    MyPrint(12, std::cout) << std::endl;
    return 0;
}

Après avoir changé le pointeur sur une référence, vous pouvez faire ceci:

#include <iostream>

std::ostream& MyPrint(int val, std::ostream& out) {
    out << val;
    return out;
}

int main(int, char**) {
    MyPrint(11, std::cout << "Value: ") << std::endl; 

    return 0;
}

La syntaxe de MyPrint est essentiellement celle d'un operator<< déroulé mais avec un argument supplémentaire.

Dans votre cas, la réponse est évidemment:

 std::cout << "Value: " << 12 << std::endl;

Si cela ne suffit pas bien, s'il vous plaît expliquer ce que la sortie que vous voulez voir.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top