2009-07-06 2 views
6

Я хочу, чтобы написать функцию, которая выводит что-то к ostream, который передается в и возвращает поток, как это:Функция, которая печатает что-то в std :: ostream и возвращает std :: 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<<?

ОБНОВЛЕНИЕ: Уточнено, каков будет желаемый результат.

UPDATE2: Некоторые люди не понимали, почему я бы напечатал такое число, используя функцию, а не печатать ее напрямую. Это упрощенный пример, и на самом деле функция печатает сложный объект, а не int.

+1

Почему вы передаете поток через указатель, а не через выделение? – 2009-07-06 16:38:31

+0

Возможно, он прочитал руководство по стилю Google и купил в этом «не использовать неконстантные параметры ссылки», который идет вокруг. –

+0

Кроме того, в чем смысл не делать 'cout <<" Значение: "<< 12;' like @Neil рекомендует? Это, кажется, самое прямое решение. –

ответ

11

Вы не можете исправить эту функцию. Ничто в спецификации не требует, чтобы компилятор оценивал вызов функции в выражении в любом конкретном порядке относительно некоторого несвязанного оператора в том же выражении. Таким образом, без изменения кода вызова, вы не можете сделать 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<< для вашего класса не подходит, например, потому что есть несколько форматов, которые вы можете распечатать, и вы хотите написать другую функцию для каждого из них, тогда вы должны либо отказаться от идеи цепной связи оператора, либо просто вызвать функцию, либо написать несколько классов, которые берут ваш объект в качестве параметра конструктора, каждый из которых имеет разные перегрузки операторов.

+0

Я знаю, что мне всегда легче разорвать потоки вниз на традиционные вызовы функций, когда я могу «Я обнял что-то, поэтому я подумал, что добавлю это для OP, если это им тоже поможет. Надеюсь, вы не против. Я думаю, что я прав, говоря, что строка std :: cout в основном сводится к cout.operator << («Значение:») .оператор << (MyPrint (12, & std :: cout)) .оператор << (std :: endl); , который может быть более простым способом визуализации того, что этот ответ говорит: – Troubadour

+0

Я, конечно же, не против: спасибо! –

+0

Я обновил вопрос, теперь он говорит, что желаемый результат будет Value: 12. – Frank

5

Вы хотите, чтобы 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; 
} 
+0

За исключением того, что это не делает то, о чем просили. – 2009-07-06 16:41:22

+0

Как так? Пожалуйста, объясни. – rlbond

+1

Ну, для начала, он не компилируется. – 2009-07-06 16:46:02

0

Во-первых, нет никаких причин, чтобы не пропустить в 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; 
} 
+0

«нет причин не пропускать в поток по ссылке». Некоторым людям не нравятся неконстантные эталонные параметры. Я не согласен с ними, но я бы не сказал, что «нет причин» для их предпочтения. –

+0

Я не вижу, как неконтентный указатель был бы предпочтительнее неконстантной ссылки в любом стандартном стандарте кодирования. –

+0

Google говорит: «Ссылки могут вводить в заблуждение, поскольку у них есть синтаксис значений, но семантика указателя» (http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml?showone=Reference_Arguments#Reference_Arguments). Я думаю, что они означают, что pass-by-value и pass-by-reference выглядят одинаково на сайте вызова, поэтому они считают, что код более читабельен, если читатели могут предположить, что все, что похоже на пропущенное значение, оставляет значение неизмененной. И, как говорится, Google безумный, как лиса. У этого есть немного слегка старомодное отношение к C++, но я думаю, что это не иррационально. –

-1

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

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

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

+1

Пример, очевидно, упрощен и показывает, что пользователь хочет понять, как цепочки потоков. –

+2

В отличие от многих людей здесь, у меня нет счастливой возможности понять «очевидный» вопрос без пробелов - мне нравится, когда все вещи прописаны. – 2009-07-06 18:50:14

+0

Я думаю, что вы должны погладить свою икону сердитым морским звездам :-( –

1

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

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

3

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

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; 
} 
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<<, но с дополнительным аргументом.

Смежные вопросы