Функция, которая печатает что-то в std::ostream и возвращает std::ostream?
Я хочу написать функцию, которая выводит что-то в 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
.
7 ответов
вы не можете исправить функцию. Ничто в спецификации не требует, чтобы компилятор оценивал вызов функции в выражении в любом определенном порядке относительно некоторого несвязанного оператора в том же выражении. Поэтому, не меняя код вызова, вы не можете сделать MyPrint()
оценить после std::cout << "Value: "
порядок слева направо является обязательным для выражений, состоящих из нескольких последовательных операторов
вы не можете достичь того же самого с бесплатными вызовами функций, потому что у них нет 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 классом с оператором friend
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;
}
нет способа сделать то, что вы ожидаете, из-за порядка, в котором оцениваются функции.
есть ли какая-то особая причина, по которой вам нужно писать прямо в поток? Если нет, просто попросите 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;
если этого недостаточно, объясните, какой вывод вы хотите увидеть.