1''
1''

Reputation: 27115

#define print(msg) std::cout << msg << std::endl

I've started using C++ recently and I've felt a strong urge to

#define print(msg) std::cout << msg << std::endl

Will this perform correctly in all situations? This is the only formulation I'm aware of that will work when there's a << in msg (e.g. "foo" << myInt). Neither

#define print(msg) std::cout << (msg) << std::endl // note: parens

nor the suggested answer

template<typename T>
void print(T const& msg) {
    std::cout << msg << std::endl;
}

work in this case. I also don't care about the efficiency of flushing the output with endl vs just using \n.

Upvotes: 3

Views: 3698

Answers (4)

Casey
Casey

Reputation: 42574

Just for fun, here's two variadic C++11 implementations of print: one that inserts spaces between the arguments, and one that does not. (Live at ideone.)

#include <iostream>

namespace with_spaces {

namespace detail {
std::ostream& print(std::ostream& os) {
    return os;
}

template <typename T>
std::ostream& print(std::ostream& os, T&& t) {
    return os << std::forward<T>(t);
}

template <typename T, typename U, typename... Args>
std::ostream& print(std::ostream& os, T&& t, U&& u, Args&&... args) {
    return print(print(os, std::forward<T>(t)) << ' ', std::forward<U>(u), std::forward<Args>(args)...);
}
}

template <typename... Args>
void print(Args&&... args) {
    detail::print(std::cout, std::forward<Args>(args)...) << std::endl;
}
}

namespace without {
namespace detail {
std::ostream& print(std::ostream& os) {
    return os;
}

template <typename T>
std::ostream& print(std::ostream& os, T&& t) {
    return os << std::forward<T>(t);
}

template <typename T, typename... Args>
std::ostream& print(std::ostream& os, T&& t, Args&&... args) {
    return print(print(os, std::forward<T>(t)), std::forward<Args>(args)...);
}
}

template <typename... Args>
void print(Args&&... args) {
    detail::print(std::cout, std::forward<Args>(args)...) << std::endl;
}
}

#include <iomanip>

int main() {
    std::cout << std::boolalpha;
    with_spaces::print(1, "foo", new int(3), 0xFFFFFFFFFFULL, 42, 0 == 1);
    without::print(1, "foo", new int(3), 0xFFFFFFFFFFULL, 42, 0 == 1);
}

It's interesting to me just how much code is necessary to accomplish what that simple one-line macro can do.

Upvotes: 2

edtheprogrammerguy
edtheprogrammerguy

Reputation: 6039

Macros are widely used, but not good practice (especially in C++) because they can hide what is really going on and make it impossible to debug your code.

Macros also bypass the type checking of the preprocessor and can lead to runtime problems.

I would suggest an inline function here if you are trying to optimize for speed.

Upvotes: 0

K-ballo
K-ballo

Reputation: 81379

Since you mention you have just started using C++ recently, I would like to show you a better alternative that the language offers:

template<typename T>
void print(T const& msg)
{
    std::cout << msg << std::endl;
}

It takes a single msg argument of any type, and it streams it out via std::cout.

As mentioned in the comments, std::endl does not only insert a new line but also flushes the stream. This is akin to printf flushing on \n. If you just want a new line, and you probably do, better do that explicitly:

std::cout << msg << '\n';

Upvotes: 5

Mark B
Mark B

Reputation: 96291

This is pretty subjective, but you write code once and read it many times. Other maintainers of the code will want to understand what you've written, so just write std::cout << msg << std::endl when that's what you mean. Don't try to make C++ look like another language.

Upvotes: 3

Related Questions