-2

In order to support logging string with << operator, I used Macro to handle it.

my_log_fun("hello"<<"world")  //In the real case, people can pass variables

And the Macro is like

#define my_log_fun(out)  \ 
   ostringstream os; \
   os << out; \
   play_with(os) \

While Macros give limitation for my continues task, is there a way to make my_log_fun in a real function which can receive parameter like "hello"<<msg<<"world"?

thundium
  • 995
  • 4
  • 12
  • 30
  • Does it have to be `<<`? Just use multiple arguments. If you really want `<<` without a macro, you probably have to do something like `log() << "hello" << "world";`. I know something (maybe QT) does this. – chris Jul 05 '15 at 14:04
  • Why do people seem to like the pre-processor? Granted it has its uses but this is not one of them – Ed Heal Jul 05 '15 at 14:05
  • What about letting your `my_log_fun()` being a function, and return an appropriate `std::ostream&` from it? – πάντα ῥεῖ Jul 05 '15 at 14:06
  • It is so convenient to use << in your code for log, isn't it? Actually there are both << and argument list implement – thundium Jul 05 '15 at 14:10
  • 1
    You may find some help in other answers, such as this one: http://stackoverflow.com/questions/511768/how-to-use-my-logging-class-like-a-std-c-stream – aslg Jul 05 '15 at 14:11
  • @EdHeal Let's why I want to get rid of it. but seems no implicit converting from "x"<<"Y" till ostringstream – thundium Jul 05 '15 at 14:12

2 Answers2

0

"is there a way to make my_log_fun in a real function which can receive parameter like << "hello"<<msg<<"world"?"

Yes there is. Instead of using a macro, I'd recommend to use a class and overloaded global operator specialized to do this:

class MyLogger {
public:
    MyLogger(std::ostream& logStream) 
    : logStream_(logStream)
    {}

    template<typename T>
    friend MyLogger& operator<<(MyLogger&, const T&);
private:
    std::ostream&  logStream_;
};

template<typename T>
MyLogger& operator<<(MyLogger& log, const T& value) {
    log.logStream_ << value;
    return log;
}

And use it:

int main() {
    MyLogger log(std::cout);

    log << "Hello" << " World!"; 
} 

See a working Demo.


Note:
You'll need to write/delegate your own stream I/O manipulator functors (like e.g. for std::endl) to get them working with the MyLogger& operator<<(MyLogger&, T) operator overload.

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
0

This is possible, but not in a way that preserves the my_log_fun("hello"<<"world") syntax. There are a few ways I can think of.

  1. Make your own stream class (probably a bad idea) or streambuf (not sure that would work).
  2. Change my_log_fun() to a function that simply returns the stream. I can't see how that would support your post-processing case, though.
  3. The C++11 approach with recursive variadic templates.

For example (untested code):

template<typename... Args> void do_my_log_fun(ostream& os, Args... args);
template<typename T> void do_my_log_fun(ostream& os, T arg) {
    os << arg;
}
template<typename T, typename... Rest>
void do_my_log_fun(ostream& os, T arg1, Rest... args) {
    do_my_log_fun(arg1);
    do_my_log_fun(args);
}
template<typename... Args> void my_log_fun(Args... args) {
    ostringstream os;
    do_my_log_fun(os, args...);
    play_with(os);
}
  1. The C approach to variadic functions. I won't go into this as it amounts to writing a function that's called like printf and would probably end up forwarding to sprintf or snprintf.
  2. Use a global stream or stream-like object.

It would look something like this:

enum LoggerProxy {logger};
template<typename T>
ostream operator<< (LoggerProxy lhs, T rhs) {
    ostringstream os;
    return os << rhs;
}
void my_log_fun(ostream& os) {
    play_with(os);
}

And you would use it like this:

my_log_fun(logger<<"hello"<<"world");

Always with logger first.

celticminstrel
  • 1,637
  • 13
  • 21
  • 1
    `3.` may be done without recursion: `{int dummy[] = {((os << args), 0)...};};` – Jarod42 Jul 05 '15 at 16:29
  • Oh, nice! I haven't done a lot with variadic templates, except for forwarding them to another non-variadic function, so I'm not yet aware of all the things you can do with parameter packs. – celticminstrel Jul 05 '15 at 16:46