Функция, которая печатает что-то в std::ostream и возвращает std::ostream?

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

  •  23-08-2019
  •  | 
  •  

Вопрос

Я хочу написать функцию, которая выводит что-то в ostream это передано, и вернуть поток, вот так:

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

Было бы удобно напечатать значение вот так и встроить вызов функции в цепочку операторов вывода, как я это сделал в main().

Однако он не работает и печатает это:

$ ./a.out
12Value: 0x6013a8

Желаемый результат будет таким:

Value: 12

Как я могу это исправить?Должен ли я определить operator<< вместо?

ОБНОВЛЯТЬ: Уточнил, какой будет желаемый результат.

ОБНОВЛЕНИЕ2: Некоторые люди не понимали, почему я печатаю такое число, используя функцию вместо того, чтобы печатать его напрямую.Это упрощенный пример, и на самом деле функция печатает сложный объект, а не int.

Это было полезно?

Решение

Вы не можете исправить функцию.Ничто в спецификации не требует, чтобы компилятор оценивал вызов функции в выражении в каком-либо определенном порядке относительно какого-либо несвязанного оператора в том же выражении.Таким образом, без изменения кода вызова вы не сможете сделать MyPrint() оценить после std::cout << "Value: "

Порядок слева направо обязателен для выражений, состоящих из нескольких последовательных операторов <<, так что это будет работать.Смысл оператора<<, возвращающего поток, заключается в том, что когда операторы объединены в цепочку, LHS каждого из них предоставляется вычислением оператора слева от него.

Вы не можете добиться того же с помощью бесплатных вызовов функций, потому что у них нет LHS. MyPrint() возвращает объект, равный std::cout, и так же std::cout << "Value: ", так что вы эффективно делаете std::cout << std::cout, который печатает это шестнадцатеричное значение.

Поскольку желаемый результат:

Value: 12

«правильное» решение — это переопределить оператор<<.Зачастую это означает, что вам нужно либо сделать его другом, либо сделать следующее:

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

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

Если переопределить operator<< для вашего класса не подходит, например, потому что существует несколько форматов, которые вы, возможно, захотите распечатать, и вы хотите написать отдельную функцию для каждого из них, тогда вам следует либо отказаться от идеи цепочки операторов и просто вызвать функцию или напишите несколько классов, которые принимают ваш объект в качестве параметра конструктора, каждый с разными перегрузками операторов.

Другие советы

Вы хотите сделать MyPrint классом с дружественным оператором<<:

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

Этот метод требует, чтобы вы вставили объект MyPrint в выбранный вами поток.Если вам ДЕЙСТВИТЕЛЬНО нужна возможность изменить активный поток, вы можете сделать это:

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

У вас есть два варианта.Во-первых, используя то, что у вас уже есть:

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

Другой вариант, более похожий на C++, заключается в замене MyPrint() с соответствующими std::ostream& operator<<.уже есть один для int, поэтому я сделаю немного сложнее:

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

Невозможно сделать то, что вы ожидаете, из-за порядка, в котором оцениваются функции.

Есть ли какая-то особая причина, по которой вам нужно писать прямо в ostream?Если нет, просто попросите MyPrint вернуть строку.Если вы хотите использовать поток внутри MyPrint для генерации вывода, просто используйте strstream и верните результат.

Во-первых, нет причин не пройти ostream по ссылке, а не по указателю:

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

Если вы действительно не хотите использовать std::ostream& operator<<(std::ostream& os, TYPE), вы можете сделать это:

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

После изменения указателя на ссылку вы можете сделать это:

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

Синтаксис для MyPrint по сути представляет собой развернутый operator<< но с дополнительным аргументом.

В вашем случае ответ очевиден:

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

Если этого недостаточно, объясните, какой результат вы хотите увидеть.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top