Funzione che consente di stampare qualcosa a std :: ostream e restituisce std :: ostream?

StackOverflow https://stackoverflow.com/questions/1087927

  •  23-08-2019
  •  | 
  •  

Domanda

Voglio scrivere una funzione che emette qualcosa ad un ostream che è passato, e restituire il torrente, in questo modo:

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;
}

Sarebbe conveniente per stampare il valore di questo tipo e incorporare la chiamata di funzione nella catena operatore di output, come ho fatto in main().

Non funziona, però, e le stampe in questo modo:

$ ./a.out
12Value: 0x6013a8

L'output desiderato sarebbe questo:

Value: 12

Come posso risolvere questo problema? Devo definire un operator<< invece?

UPDATE:. Chiarito quale sarebbe l'output desiderato

UPDATE2: Alcune persone non capivano perché dovrei stampare un numero del genere, utilizzando una funzione invece di stampare direttamente. Questo è un esempio semplificato, e in realtà la funzione stampa un oggetto complesso piuttosto che un int.

È stato utile?

Soluzione

Non si può risolvere la funzione. Niente nella specifica richiede un compilatore per valutare una chiamata di funzione in un'espressione in un ordine particolare rispetto a qualche operatore indipendente nella stessa espressione. Quindi, senza cambiare il codice chiamante, non è possibile effettuare MyPrint() valutare dopo std::cout << "Value: "

ordine da sinistra a destra ha il compito per le espressioni costituiti da più consecutivi << gli operatori, in modo che funzionerà. Il punto di operatore << ritornare il flusso è che quando gli operatori sono concatenati, il LHS di ognuno viene fornita dalla valutazione dell'operatore alla sua sinistra.

Non si può ottenere la stessa cosa con le chiamate funzione liberi, perché non hanno un LHS. MyPrint() restituisce un oggetto pari a std::cout, e così fa std::cout << "Value: ", così si sta effettivamente facendo std::cout << std::cout, che è la stampa di tale valore esadecimale.

Poiché l'uscita desiderata è:

Value: 12

la cosa "giusta" da fare è infatti quello di ignorare operatore <<. Questo significa che spesso è necessario o renderlo un amico, o di fare questo:

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

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

Se operator<< prioritario per la classe non è appropriato, ad esempio perché ci sono più formati che si potrebbe desiderare di stampare, e si vuole scrivere una funzione diversa per ognuno, allora si dovrebbe o rinunciare all'idea di operatore di concatenamento e basta chiamare la funzione, oppure scrivere più classi che prendono l'oggetto come un parametro del costruttore, ciascuno con differenti overload dell'operatore.

Altri suggerimenti

Si vuole fare MyPrint una classe con amico operatore <<:

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;
}

Questo metodo richiede di inserire l'oggetto MyPrint nel flusso di vostra scelta. Se si ha realmente bisogno la possibilità di cambiare il flusso è attiva, si può fare questo:

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;
}

Sono disponibili due opzioni. Il primo, con quello che già hai è:

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

L'altro, che è più C ++ - come, è quello di sostituire MyPrint() con il std::ostream& operator<< appropriata. C'è già una per int, quindi mi farò uno appena un po 'più complessa:

#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;
}

Non c'è modo di fare ciò che ci si aspetta a causa della fine delle funzioni vengono valutate in.

C'è un motivo particolare è necessario scrivere direttamente al ostream in quel modo? In caso contrario, basta avere MyPrint restituire una stringa. Se si desidera utilizzare un flusso all'interno MyPrint per generare l'output, basta usare uno strstream e restituire il risultato.

In primo luogo, non v'è alcuna ragione per non passare nel ostream per riferimento anziché un puntatore:

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

Se proprio non si vuole utilizzare std::ostream& operator<<(std::ostream& os, TYPE), si può fare questo:

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

Dopo aver cambiato il puntatore a un punto di riferimento, si può fare questo:

#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 sintassi per MyPrint è essenzialmente quella di un operator<< srotolato, ma con un argomento in più.

Nel tuo caso la risposta è ovviamente:

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

Se questo non è sufficiente, si prega di spiegare che cosa output che si desidera vedere.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top