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.
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';
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.
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.
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.
Related
Let's suppose I have the following class in an header file header.h:
#pargma once
#include <type_traits>
#include <iostream>
#include <sstream>
struct foo
{
// Utils struct
template <class T, class... Ts>
struct is_any: std::disjunction <std::is_same <T, Ts>... >{};
// Standard case
template <class T_os, class T, class... Args, typename = std::enable_if_t<is_any
<T_os, std::ostream, std::ostringstream>::value>>
const foo& operator () ( T_os& os, const T& first, const Args&... args ) const { os << "hello"; return *this; }
// Default std::ostream = std::cout case
template <class T, class... Args>
const foo& operator () ( const T& first, const Args&... args ) const { std::cout << "hello"; return *this; }
};
I defined a struct in which I overloaded the () operator two times: in the "standard case" the template is enabled if the T_os type is one of this list (std::ostream, std::ostringstream) and a message is sent to output using the T_os os object. In the "Default std::ostream = std::cout case" the template is called if T_os is not explicitly present and a message is sent to output using the std::ostream std::cout object.
A simple usage in main is:
#include "header.h"
int main()
{
foo foo_obj;
// Standard case
foo_obj ( std::cout, "first", "second" );
// Default std::ostream = std::cout case
foo_obj ( "first", "second" );
}
I want to know if it would be possible to merge the "standard case" operator () overload within the "Default std::ostream = std::cout case" operator () overload, in order to be able to perform the two operations shown in main using only an operator () overload instead of two. Thanks.
You could make operator() a front-end for the real implementation. You can then make it forward the arguments to the real implementation and add std::cout if needed.
Example:
struct foo {
template <class T, class... Args>
const foo& operator()(T&& first, Args&&... args) const {
if constexpr (std::is_base_of_v<std::ostream, std::remove_reference_t<T>>) {
// or std::is_convertible_v<std::remove_reference_t<T>*, std::ostream*>
// first argument is an `ostream`, just forward everything as-is:
op_impl(std::forward<T>(first), std::forward<Args>(args)...);
} else {
// add `std::cout` first here:
op_impl(std::cout, std::forward<T>(first), std::forward<Args>(args)...);
}
return *this;
}
private:
// implement the full operator function here. `os` is an `ostream` of some sort:
template <class S, class... Args>
void op_impl(S&& os, Args&&... args) const {
(..., (os << args << ' '));
os << '\n';
}
};
Demo
I used is_base_of_v<std::ostream, ...> instead of is_same to make it use any ostream (like an ostringstream or ofstream) if supplied as the first argument.
Maybe a solution with constexpr if (see here) and fold expressions will help.
Something like for example the below.
#include <type_traits>
#include <iostream>
#include <sstream>
template <class TFirst, class... TsRest>
void print(TFirst&& first, TsRest&& ... rest) {
if constexpr (std::is_same_v <std::remove_cvref_t<TFirst>, std::ostringstream> or
std::is_same_v <std::remove_cvref_t<TFirst>, std::ostream>) {
((first << rest << ' '), ...);
}
else {
std::cout << first << ' ';
((std::cout << rest << ' '), ...);
}
}
int main() {
print(1, 2);
std::ostringstream oss{};
print(oss, 3, 4);
std::cout << "\n\n" << oss.str() << "\n\n";
}
Maybe, this could give you an idea . . .
I have written myself the following function:
template <class Stream>
inline Stream& Print(Stream& in) { return in;}
template <class Stream, class Arg1, class... Args>
inline Stream& Print(Stream& sout, Arg1&& arg1, Args&&... args)
{
sout << arg1;
return Print(sout, args...);
}
It should make it useful to replace code like:
cout << "This took " << ns << " seconds with " << np << " packets.\n";
with
Print(cout, "This took ", ns, " seconds with ", np, " packets.\n");
And everything works fine, except that this function doesn't "tolerate" some manipulators. What is funny, only some of them. If you replace, for example, " packets.\n" with " packets.", endl, it will no longer compile. Although hex or setw(20) is fine. Where is the problem?
std::endl is a function template.
So it cannot be deduced as for overloaded functions.
static_cast<std::ostream& (*)(std::ostream&)>(&std::endl)
would select correct overload.
using Manipulator = std::ostream& (*)(std::ostream&);
Print(std::cout, "This took ", ns, " seconds with ", np, " packets.", Manipulator(std::endl));
Demo
Since C++14, you might even not hard code type of stream with an helper:
template <typename T>
struct ManipulatorImpl
{
ManipulatorImpl(T t) : t(t) {}
T t;
};
template <typename T>
std::ostream& operator << (std::ostream& os, ManipulatorImpl<T> m)
{
return m.t(os);
}
template <typename T>
ManipulatorImpl<T> make_ManipulatorImpl(T t) { return {t}; }
#define Manipulator(name) make_ManipulatorImpl([](auto& os) -> decltype((name)(os)) { return (name)(os); })
Demo
I can't explain the exact reason, but if I do something like this it doesn't throw an error:
endl<char, char_traits<char>>
My guess is that it doesn't seem to be able to do template type parameter inference.
The ostream is:
using ostream = basic_ostream<char, char_traits<char>>;
I have the following code that works, but I am confused about how it works.
template<typename ...Args>
void print(Args&&... args) {
(std::cout << ... << std::forward<Args>(args)) << '\n';
}
int main()
{
print(1,2.0,"3");
}
output:
123
My confusion:
I would expect 321 printed.
I would like to have this order:
cout << forward(args) << ...
but I can not get that to compile...
The position of ... specifies left or right associativity, but doesn't change the order of arguments - it lets you choose between (std::cout << x) << y and std::cout << (x << y). The later likely would not compile.
If you want to print values in the reversed order you need to use some trick. Here is the example:
#include <type_traits>
#include <iostream>
template <typename T>
struct ReversePrinter
{
ReversePrinter(T val) : val(val) { }
template <typename U>
ReversePrinter<T> operator<<(const ReversePrinter<U>& other) const
{
std::cout << other.val;
return *this;
}
T val;
};
template <typename T>
std::ostream& operator<<(std::ostream& stream, const ReversePrinter<T>& val)
{
return stream << val.val;
}
template <typename... Args>
void print(Args... args)
{
std::cout << (ReversePrinter(args) << ...);
}
int main()
{
print(100, 200, 300.0); //prints 300200100
}
Fold expressions respect the precedence and associativity of the operator you use. But for certain operators you can do more creative left and right folds. The only variable to account for is the sequencing of the operands. C++17 introduced a happens before relation between the right and left side of assignment operators, so they act more intuitively. The right side, and all associated side effects must happen first.
So a completely self contained solution to your question can look like this:
template <typename... Args>
void print(Args&& ...args) {
int dum = 0;
(... = (std::cout << args, dum));
}
Here it is, live.
It's using a comma to print, while assigning dum to itself in a way that forces the evaluation order we want.
With few trickeries, (can't come anything better at the moment) you could do following:
Not sure if there's any straight forward way
// Your original function
template<typename ...Args>
void print(Args&&... args) {
(std::cout << ... << std::forward<Args>(args)) << '\n';
}
template<typename ...Args>
struct changeorder;
template<>
struct changeorder<>
{
template<typename ...OtherArgs>
static void invoke(OtherArgs const&... otherargs)
{
print(otherargs...);
}
};
template<typename T, typename ...Args>
struct changeorder<T, Args...>
{
template<typename ...OtherArgs>
static void invoke(T const& t, Args const&... args,
OtherArgs const&... otherargs)
{
// 1st parameter send first
changeorder<Args...>::invoke(args..., t, otherargs...);
}
};
template<typename A, typename ...Args>
void reverseprint(A const& a, Args const&... args)
{
changeorder<Args...>::invoke(args..., a);
}
Demo Here
The standard go-to solution for template-magic is std::index_sequence.
And for making arguments indexable one uses std::tuple.
template <std::size_t... N, class T>
void print_reverse_impl(std::index_sequence<N...>, std::ostream& os, T t) {
(os << ... << std::get<std::tuple_size_v<T> - N - 1>(t));
}
template <class... T>
void print_reverse(std::ostream& os, T&&... t) {
print_reverse_impl(std::make_index_sequence<sizeof...(t)>(), os, std::forward_as_tuple(t...));
}
Still, if you have static_for() in your tool-box (you really should), this is simpler:
template <class... T>
void print_reverse(std::ostream& os, T&&... t) {
static_for<sizeof...(t)>([&](auto n){
os << std::get<sizeof...(t) - n - 1>(std::forward_as_tuple(t...));
});
}
With C++20, one could also write it as:
void print_reverse(std::ostream& os, auto&&... t) {
[&]<auto... N>(std::index_sequence<N...>, auto all){
(os << ... std::get<sizeof...(t) - N - 1>(all));
}(std::make_index_sequence<sizeof...(t)>(), std::forward_as_tuple(t...));
}
As an aside, I cut out all the calls to std::forward, because those rvalue-references would just be reduced down to lvalue-references by the standard-library anyway.
I have below code to convert all arguments passed to a function into csv:
void Parse(ostream& os)
{
}
template <typename T, typename... Args>
void Parse(ostream& os, T t, Args... args)
{
os << *t << ',';
Parse(os, args...);
}
While this works fine for all data types for what I am doing, I want some special handling for char data types. If there is a char parameter(for eg. 0) I want to convert it into ascii(48 for zero) and then add it to the csv. I cannot modify it at the caller place. How can I handle it in the parameter pack?
You just define an overloaded function (details::print() in the example below) for dealing with a single datum and then join them using a fold expression:
namespace details {
template<typename T>
void print(std::ostream&os, T const&x)
{ os << x << ','; } // print any value
template<typename T>
void print(std::ostream&os, T*x)
{ print(os,*x); } // print value pointed to
template<typename T>
void print(std::ostream&os, const T*x)
{ print(os,*x); } // print value pointed to
void print(std::ostream&os, const char*x)
{ os << x << ','; } // print C-style string
}
template<typename...Args>
void parse(std::ostream&os, const Args& ...args)
{
(details::print(os,args) , ...); // fold expression
}
int main()
{
double x=3.1415;
parse(std::cout,"fun",42,'d',&x);
}
output: fun,42,d,3.1415,
You can suppress the trailing comma by the method of Jarod's answer (though your original post didn't suppress it).
template <typename T, typename... Args>
void Parse(ostream& os, T t, Args... args)
{
if constexpr(std::is_same_v<T, char>)
{
os << to_ascii(t) << ',';
}
else
{
os << *t << ',';
}
Parse(os, args...);
}
Since you use recursion to handle the parameter pack, you can add two overloads
void Parse(ostream& os) {} /* As before. */
void Parse(ostream& os, char *c)
{
os << handleChar(*c) << ",";
}
template <class T> void Parse(ostream& os, T t)
{
os << *t << ",";
}
and change the original variadic function definition to
template <typename T, typename... Args>
void Parse(ostream& os, T t, Args... args)
{
Parse(os, t);
Parse(os, args...);
}
The compiler will prefer this non-templated function when calling Parse with a two arguments, the second being char*.
I would split iteration from real action:
template <typename T>
void Handle(std::ostream& os, const char*& sep, T arg)
{
os << sep << arg;
sep = ",";
}
void Handle(std::ostream& os, const char*& sep, char arg)
{
os << sep << (int)arg;
sep = ",";
}
template <typename... Args>
void Parse(std::ostream& os, Args... args)
{
const char* sep = "";
(Handle(os, sep, args), ...);
}
I write a variadic template to print all the arguments with recursion:
#include <iostream>
using std::ostream; using std::istream;
using std::cin; using std::cout; using std::endl;
template <typename T, typename... Args>
ostream &myprint(ostream &os, const T &t, const Args&... rest) {
if (sizeof...(rest)) {
os << t << ", ";
return myprint(os, rest...);
}
else
return os << t;
}
int main(int argc, char *argv[]) {
myprint(cout, "hello");
return 0;
}
But when I compiles it with g++ -std=c++1y, it complains:
error: no matching function for call to ‘myprint(std::ostream&)’
return myprint(os, rest...);
In the function myprint, I have checked the value of sizeof...(rest). And when it is 0, it will not call myprint(os, rest...). So I don't know why it will call myprint(std::ostream&).
And I have also searched for the related question, I have found that it needs a base case. But why do I need a base case, and can't sizeof... work in a variadic template?
And for the simple indefinite recursive case:
template <typename T, typename... Args>
ostream &myprint(ostream &os, const T &t, const Args&... rest) {
os << t << ", "; // print the first argument
return print(os, rest...); // recursive call; print the other arguments
}
The code above can't be compiled at all for the same error.
For the if statement you used, both the statement-true and statement-false must be valid, whether the condition yields to the result of true or false.
You can use constexpr if since C++17; when the value of condition is false, the statement-true will be discarded. e.g.
if constexpr (sizeof...(rest)) {
os << t << ", ";
return myprint(os, rest...);
}
else
return os << t;
If you can't use C++17, you can add another template overload for the case that the number of arguments is only one, to stop the recursion, e.g.
template <typename T>
ostream &myprint(ostream &os, const T &t) {
return os << t;
}
template <typename T, typename... Args>
ostream &myprint(ostream &os, const T &t, const Args&... rest) {
os << t << ", ";
return myprint(os, rest...);
}
LIVE
songyuanyao's answer explains why it's invalid and provides a solution for C++17. Alternatively, you could have a base case to myprint prior to that.
template <typename T>
ostream &myprint(ostream &os, const T &t) {
return os << t;
}
template <typename T, typename... Args>
ostream &myprint(ostream &os, const T &t, const Args&... rest) {
os << t << ", ";
return myprint(os, rest...);
}