Pergunta

Eu quero escrever uma função que saídas algo a um ostream que é passado, e retornar o fluxo, como este:

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

Seria conveniente para imprimir o valor como este e incorporar a chamada de função na cadeia operador de saída, como eu fiz no main().

Ele não funciona, no entanto, e imprime o seguinte:

$ ./a.out
12Value: 0x6013a8

A saída desejada seria esta:

Value: 12

Como posso corrigir isso? Eu tenho que definir uma operator<< vez?

UPDATE:. Esclarecido que a saída desejada seria

UPDATE2: Algumas pessoas não entendem por que eu iria imprimir um número como esse, usando uma função em vez de imprimi-lo diretamente. Este é um exemplo simplificado, e, na realidade, a função imprime um objecto complexo em vez de um int.

Foi útil?

Solução

Você não pode consertar a função. Nada na especificação exige um compilador para avaliar uma chamada de função em uma expressão em qualquer ordem particular no que diz respeito a algum operador não ligado na mesma expressão. Então, sem alterar o código de chamada, você não pode fazer MyPrint() avaliar após std::cout << "Value: "

ordem da esquerda para a direita está mandatado para expressões que consistem em vários << operadores consecutivos, de modo que vai funcionar. O ponto de operador << retornar o fluxo é que quando os operadores estão acorrentados, os LHS de cada um é fornecido pela avaliação do operador à sua esquerda.

Você não pode conseguir a mesma coisa com chamadas de função livres, porque eles não têm um LHS. MyPrint() retorna um objeto igual a std::cout, e assim faz std::cout << "Value: ", então você está fazendo efetivamente std::cout << std::cout, que é a impressão de que o valor hexadecimal.

Desde a saída desejada é:

Value: 12

a coisa "certa" a fazer é realmente para operador override <<. Isto significa frequentemente você precisa se quer torná-lo um amigo, ou fazer isso:

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

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

Se substituindo operator<< para sua classe não é o caso, por exemplo, porque existem vários formatos que você pode querer imprimir, e você quer escrever uma função diferente para cada um, então você deve ou desistir da idéia de operador de encadeamento e apenas chamar a função, ou então escrever várias classes que tirar o objeto como um parâmetro de construtor, cada um com diferentes sobrecargas de operador.

Outras dicas

Você quer fazer MyPrint uma classe com o amigo operador <<:

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

Este método requer que você inserir o objeto MyPrint na corrente de sua escolha. Se você precisa REALMENTE a capacidade de mudança que fluxo está ativa, você pode fazer isso:

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

Você tem duas opções. O primeiro, usando o que você já tem é:

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

A outra, que é mais C ++ - como, é substituir MyPrint() com o std::ostream& operator<< apropriado. Já existe um para int, por isso vou fazer um apenas um pouco mais complexo:

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

Não há nenhuma maneira de fazer o que você está esperando lá por causa da ordem das funções são avaliadas no.

Há alguma razão especial que você precisa para escrever diretamente para o ostream assim? Se não, só tem MyPrint retornar uma string. Se você quiser usar um fluxo dentro MyPrint para gerar a saída, basta usar um strstream e retornar o resultado.

Em primeiro lugar, não há nenhuma razão para não passar na ostream por referência em vez de um ponteiro:

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

Se você realmente não quiser usar std::ostream& operator<<(std::ostream& os, TYPE), você pode fazer isso:

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

Depois de alterar o ponteiro para uma referência, você pode fazer isso:

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

A sintaxe para MyPrint é essencialmente a de um operator<< desenrolado mas com um argumento extra.

No seu caso, a resposta é, obviamente:

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

Se isso não é bom o suficiente, por favor explicar o que de saída que você quer ver.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top