2

I have a lot of couts and so I would like to be able to make a function that can take just three arguments. The function would print them out to the screen just as cout does like this:

print( 5, " is a ", "number" );

// should do the same thing as

cout << 5 << " is a " << "number" << endl;

I'm not asking anyone to do it. I'm just looking for a way to be able to. But if you can provide the code that would be good as well. Does anyone have any advice? Thanks.

Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
David G
  • 94,763
  • 41
  • 167
  • 253
  • 3
    1) What have you tried, 2) how would the function be better thatn `cout << ...`, and 3) have you heard of templates? – Beta Jul 16 '12 at 20:37

5 Answers5

14
template <typename T0, typename T1, typename T2>
void print(T0 const& t0, T1 const& t1, T2 const& t2)
{
    std::cout << t0 << t1 << t2 << std::endl;
}
James McNellis
  • 348,265
  • 75
  • 913
  • 977
  • Scott Meyers (in Effective C++) recommends that you use pass by const ref for all types, except for builtin types (char, int, double, etc.), for iterators and for function objects (classes deriving from std::*_function). –  Jul 16 '12 at 20:43
  • What does the `const& t0` do? Please explain in layman terms as I am not quite proficient in c++. – David G Jul 16 '12 at 20:45
  • @0A0D: That is true, and given the specific example in the original question, one might prefer to pass by value (one might also prefer not to use a template, depending on what the types of the arguments are). In a template, though, the norm is to accept by `const&` instead of by value, to handle the "worst case." – James McNellis Jul 16 '12 at 20:50
  • @JamesMcNellis: Do you have a reference on the norm? I am interested in reading more. –  Jul 16 '12 at 20:51
  • 1
    @David: It is a const-qualified reference. For more, I would recommend [a good introductory C++ text](http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). – James McNellis Jul 16 '12 at 20:52
  • 1
    @0A0D: Off the top of my head, I can't think of an "official" reference. See [this question](http://stackoverflow.com/questions/4876913/template-pass-by-value-or-const-reference-or) for a few reasons why `const&` (or `&&` in C++11) is usually preferable. – James McNellis Jul 16 '12 at 20:53
  • Nitpick: your function's arguments go from t0 to t2, yet you output to `cout` variables from t1 to t3. – eq- Jul 18 '12 at 19:19
  • @eq-: Thanks, fixed. (I'm not very good at counting; I usually make my computer count things for me.) – James McNellis Jul 18 '12 at 20:23
5

I would like to be able to make a function that can take just three arguments

Are you sure? C++11 affords us much more power than that.

void print()
{
    std::cout << std::endl;
}

template<typename T, typename... Args>
void print(const T & val, Args&&... args)
{
    std::cout << val;
    print(args...);
}
Benjamin Lindley
  • 101,917
  • 9
  • 204
  • 274
  • I said I wanted just three arguments because I was afraid the examples given to me depicting functions that can take unlimited arguments would be too complex for me to grasp. Is this code supposed to work as-is? I ran it and it gave me the error: `expected ',' or '...' before '&&' token'` – David G Jul 16 '12 at 21:28
  • @David: What compiler are you using? – Benjamin Lindley Jul 16 '12 at 21:29
  • I'm using the built-in compiler from CodeBlocks. – David G Jul 16 '12 at 21:29
  • I forgot to mention that I got a warning that said `variadic templates only available with -std=c++0x or -std=gnu++0x` I don't know what this means. – David G Jul 16 '12 at 21:33
  • @David: That's probably GCC, though I don't know which version. If you can figure out how to add the option `"-std=c++0x"` to the command line, then do that. If you have no idea what I'm talking about, then go on to the codeblocks forums, [here](http://forums.codeblocks.org/), and see if they can help you. Ask them, "How do I set up codeblocks to work with C++11?", they should be able to help you. (**Edit**) By your other comment, I see you definitely have a GCC version that supports the option. You just need to figure out how to add it. – Benjamin Lindley Jul 16 '12 at 21:35
4

You can do it with templates:

template<typename T, typename S, typename U>
print(T x, S y, U z)
{
    std::cout << x << y << z;
}

EDIT: If you're expecting to pass complex types (not just int or char *) you should follow James' answer and use const references.

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
2

you could use macros... (if you want to do that, can be ugly sometimes)

#define PRINT(x,y,z) cout << (x) << (y) << (z) << endl;
Misch
  • 10,350
  • 4
  • 35
  • 49
2

If you are looking to simplify the specific task of printing three items, you can do it using a #define macro:

#define print(A,B,C) cout << (A) << (B) << (C) << endl

If you prefer a function-call syntax, consider using C-style output instead: printf is a "first-class member" of the C++ standard library, there is no reason to shy away from it when it makes sense in your specific application:

printf("%d %s %s\n", 5, "is a", "number");

The advantage of printf approach is that it is not limited to any specific number of arguments.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • `print(a++, "is a", a++);` is worse than unspecified, it is undefined, and it would be even if `print` was a function instead of a macro. But that's not the function/macro's fault, it is the fault of the caller. – Benjamin Lindley Jul 16 '12 at 21:02
  • @BenjaminLindley You are correct on that, the reference is of no interest as far as this question is concerned. I edited the answer to remove it, thanks! – Sergey Kalinichenko Jul 16 '12 at 21:35