Fold expressions and cout - c++

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.

Related

"Merge" two signatures of operator () overload into one in a template class, how?

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 . . .

Template specialisation on substitution failure

Consider this function:
template<typename T>
void f(T c) {
std::cout<<c<<std::endl;
}
You see that it will not compile for types which does not have an operator<< overload.
Now I want to write a function that acts like a fallback for this case.
/*Fallback*/
template<>
void f(T c) {
std::cout<<"Not Printing"<<std::endl;
}
How must this function be defined to do the job?
Pre-C++20
To have these overloads work in a fallback way, we can start by defining a trait that detects the validity of the expression involving operator <<
namespace detail {
template<typename T, typename = void>
struct streamable : std::false_type{};
template<typename T>
struct streamable<T, decltype(std::declval<std::ostream&>() << std::declval<T&>(), void())> : std::true_type {};
}
It's just your typical use of the detection idiom with as little extra library support as possible. Depending on the standard you are building against, this may be written in other ways (for instance std::void_t can be used, if available).
Now, the two overloads can be specified rather simply:
template<typename T>
auto f(T c) -> std::enable_if_t<detail::streamable<T>::value, void> {
std::cout<<c<<std::endl;
}
template<typename T>
auto f(T c) -> std::enable_if_t<!detail::streamable<T>::value, void> {
/// other code
}
Post C++20, concepts and constraints make it a whole lot easier. It can even be written ad-hoc:
template<typename T>
requires requires(std::ostream& os, T& c) { os << c; }
void f(T c) {
std::cout<<c<<std::endl;
}
template<typename T> // No extra step, subsumed by the above when possible
void f(T c) {
// other code
}
With concepts (C++20), we can achieve this like so:
template<typename T>
concept Streamable = requires(T t){std::declval<std::ostream&>() << t; };
template<Streamable T>
void f(T c) { std::cout << c << std::endl; }
/*Fallback*/
template<typename T>
void f(T c) { std::cout << "fallback" < <std::endl; }
Demo
Test:
struct Foo{};
int main()
{
Foo foo;
f(foo); // prints "fallback"
int a = 42;
f(a); // prints "42"
}
If you want to make doubly sure that your fallback will only happen if your type is not Streamable, you can constrain it, too:
template<typename T> requires (!Streamable<T>)
void f(T c) { /*...*/ }
You have several options of doing this. Arguably the most elegant way is to define your own type trait (similar to the ones in type_traits).
Let's define a is_streamable type trait. It takes two template arguments: S is the data type of the file stream (e.g. std::ostream or std::fstream or any other type that defines a custom streaming operator that is compatible with T) and secondly the data type of the object to be streamed into this file stream T:
template<typename S, typename T, typename = void>
struct is_streamable : std::false_type {
};
template<typename S, typename T>
struct is_streamable<S, T, decltype(std::declval<S&>() << std::declval<T&>(), void())> : std::true_type {
};
So far this type trait compiles with C++11 and onwards. For C++14 and later we can create a convenient alias for it similar to other type traits in C++17:
template <typename S, typename T>
static constexpr is_streamable_v = is_streamable<S,T>::value;
This type trait will now be the basis for the next step which will make use of SFINAE (C++11 onwards), constexpr if (C++17 onwards) or concepts (C++20).
In C++11 you could achieve this with either by putting the different implementations into partial specialisations of the same struct and call it with a helper function:
class f_imp {
};
template <typename T>
class f_imp<T,true> {
public:
static constexpr void imp(T c) {
std::cout << "streamable: " << c << std::endl;
}
};
template <typename T>
class f_imp<T,false> {
public:
static constexpr void imp(T c) {
std::cout << "not streamable" << std::endl;
}
};
template <typename T>
void f(T c) {
return f_imp<T,is_streamable<std::ostream,T>::value>::imp(c);
}
Try it here!
Alternatively you could apply SFINAE either by adding a second input parameter or applying it to the return type:
template<typename T, typename std::enable_if<is_streamable<std::ostream,T>::value>::type* = nullptr>
void f(T t) {
std::cout << "streamable" << std::endl;
}
template<typename T, typename std::enable_if<!is_streamable<std::ostream,T>::value>::type* = nullptr>
void f(T t) {
std::cout << "not streamable" << std::endl;
}
Try it here!
In C++17 you can actually use a constexpr if to avoid adding a second template argument and overloading of the function altogether. You can insert all the code inside the function and use if constexpr in combination with std::is_same_v and our is_streamable_v to decide at compile time which branch of our code each template type should take. This is in particular convenient if adding two specialisations would result in duplicate code but it might be harder to read.
template<typename T>
void f(T c) {
if constexpr (is_streamable_v<std::ostream,T>) {
std::cout << "streamable:" << c << std::endl;
} else {
// Fallback
std::cerr << "not streamable" << std::endl;
}
return;
}
Try it here!
Finally in C++20 you could use this type trait to define a concepts such as streamable and not_streamable:
template <typename T>
concept streamable = is_streamable_v<std::ostream,T>;
template <typename T>
concept not_streamable = !streamable<T>;
Then you can go on to apply them to your two overloads of the functions
template <streamable T>
void f(T c) {
std::cout << "streamable: " << c << std::endl;
}
template <not_streamable T>
void f(T c) {
std::cout << "not streamable" << std::endl;
}
Try it here!
Be aware that you will have to also apply the same logic to any custom streaming operator of a templated class, e.g. of a templated vector. Instead of declaring the operator for any template parameter typename T you would have to only declare it for streamable element types only. In C++20 for example with said streamable concept:
template <streamable T>
std::ostream& operator << (std::ostream& os, std::vector<T> const& vec) {
for (auto const& v: vec) {
os << v << " ";
}
return os;
}
Otherwise - as the template argument to the is_streamable operator is std::vector<T> as a whole - the compiler sees the operator << for std::vector<T> without checking if it would result in a compilation error for an unstreamable type T which does not define the operator << itself.
Try it here!

Differentiate between user type and primitives

I'm trying to differentiate between user types and primitive types in a variadic template.
I have tried overloading binary operator, but that only says that there's no fitting overload for 'user types'...
template <typename T>
void PrintParams(T t)
{
if (IsAUserType)
std::cout << typeid(t).name();
else
std::cout << t;
}
template <typename First, typename... Rest>
void PrintParams(First first, Rest... rest)
{
if (IsAUserType)
std::cout << typeid(first).name();
else
std::cout << first;
PrintParams(rest...);
}
// If you know what to do with this, then that would also be very helpful...
//Overload << operator for user types
//template <typename T>
//friend std::ostream& operator<< (std::ostream& os, T t)
//{
//
//if (std::is_fundamental<t>::value)
//std::clog << t;
//else
//std::clog << typeid(t).name();
//}
expected result for input like (class test, 3.4, "string") would be
"test3.4string"
You could split your single argument function up in two and use SFINAE to enable the correct one depending on if the argument is a fundamental type or not:
template<typename T, typename std::enable_if<std::is_fundamental<T>::value, int>::type = 0>
void PrintParams(T t) {
std::cout << t;
}
template<typename T, typename std::enable_if<!std::is_fundamental<T>::value, int>::type = 0>
void PrintParams(T t) {
std::cout << typeid(t).name();
}
template<typename First, typename... Rest>
void PrintParams(First first, Rest... rest) {
PrintParams(first); // ... and call the single argument version here
std::cout << ",";
PrintParams(rest...);
}
Another way would be to check if the type supports streaming using operator<< instead of checking that it's a fundamental type. That would make streaming work for classes (like std::string and user defined ones too).
#include <iostream>
#include <type_traits>
#include <typeinfo>
#include <utility>
// SFINAE support
namespace detail {
template<class>
struct sfinae_true : std::true_type {};
template<class S, class T>
static auto test_lshift(int)
-> sfinae_true<decltype(std::declval<S>() << std::declval<T>())>;
template<class S, class T>
static auto test_lshift(long) -> std::false_type;
} // namespace detail
template<class T>
struct has_ostream : decltype(detail::test_lshift<std::ostream, T>(0)) {};
// using the SFINAE support stuff
template<typename T, typename std::enable_if<has_ostream<T>::value, int>::type = 0>
void PrintParams(const T& t) {
std::cout << "Type: " << typeid(t).name() << "\n"
<< " supports operator<< Value = " << t << "\n";
}
template<typename T, typename std::enable_if<!has_ostream<T>::value, int>::type = 0>
void PrintParams(const T& t) {
std::cout << "Type: " << typeid(t).name() << "\n"
<< " does NOT support operator<<\n";
}
template<typename First, typename... Rest>
void PrintParams(First first, Rest... rest) {
PrintParams(first);
PrintParams(rest...);
}
// example classes
class Foo { // will not support streaming
int x = 5;
};
class Bar { // this should support streaming
int x = 10;
friend std::ostream& operator<<(std::ostream&, const Bar&);
};
std::ostream& operator<<(std::ostream& os, const Bar& b) {
return os << b.x;
}
// testing
int main() {
int i = 2;
Foo f;
Bar b;
std::string s = "Hello world";
PrintParams(i, f, b, s);
}
Possible output:
Type: i
supports operator<< Value = 2
Type: 3Foo
does NOT support operator<<
Type: 3Bar
supports operator<< Value = 10
Type: NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
supports operator<< Value = Hello world
I think std::is_class can replace your IsAUserType.
https://en.cppreference.com/w/cpp/types/is_class
Primitive data types include integer , character , void , float etc..which are defined already inside the language i.e , user can use these data types without defining them inside the language.
User defined data types are the data types which user have to define while or before using them.

Parameter packs with specialization for one data type

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), ...);
}

template looping through tuple

I'm playing with variadic templates and I'm currently trying to implement operator<< for tuple.
I've tried the following code but it doesn't compile (GCC 4.9 with -std=c++11).
template<int I, typename ... Tlist>
void print(ostream& s, tuple<Tlist...>& t)
{
s << get<I>(t) << ", ";
if(I < sizeof...(Tlist)){
print<I+1>(s,t);
}
}
template<typename ... Tlist>
ostream& operator<<(ostream& s, tuple<Tlist...> t)
{
print<0>(s,t);
return s;
}
The error message is very cryptic and long, but it basically says that there is no matching function call for get. Can someone explain to me why?
Thanks.
EDIT:
Here is the template instantiation I'm using
auto t = make_tuple(5,6,true,"aaa");
cout << t << endl;
Code in an if (blah) { block } is compiled and must be valid even if the condition blah is false.
template<bool b>
using bool_t = std::integral_constant<bool, b>;
template<int I, typename ... Tlist>
void print(std::ostream& s, std::tuple<Tlist...> const& t, std::false_type) {
// no more printing
}
template<int I, typename ... Tlist>
void print(std::ostream& s, std::tuple<Tlist...> const& t, std::true_type) {
s << std::get<I>(t) << ", ";
print<I+1>(s, t, bool_t<((I+1) < sizeof...(Tlist))>{});
}
template<typename ... Tlist>
std::ostream& operator<<(std::ostream& s, std::tuple<Tlist...> const& t)
{
print<0>(s,t, bool_t<(0 < sizeof...(Tlist))>{});
return s;
}
should work. Here we use tag dispatching to control which overload we recursively call: the 3rd argument is true_type if I is a valid index for the tuple, and false_type if not. We do this instead of an if statement. We always recurse, but when we reach the end of the tuple, we recurse into the terminating overload.
live example
As an aside, it is ambiguous if overloading << for two types defined in std is compliant with the standard: it depends if std::tuple<int> is a "user defined type" or not, a clause that the standard does not define.
On top of that, it is considered best practice to overload operators for a type within the namespace of that type, so it can be found via ADL. But, overloading << inside std is illegal under the standard (you cannot inject new overloads into std). The result can be somewhat surprising behavior in some cases, where the wrong overload is found, or an overload is not found.
You have to use specialization or SFINAE as the branch even if it is not taken generates the instantiation:
template<int I, typename ... Tlist>
void print(ostream& s, tuple<Tlist...>& t)
{
s << get<I>(t) << ", ";
if(I < sizeof...(Tlist)){
print<I+1>(s,t); // Generated even if I >= sizeof...(Tlist)
}
}
And so you would have infinite instantiation of print if get<sizeof...(Tlist)> doesn't produce an error sooner.
You may wrote it without recursion with:
template<std::size_t ... Is, typename Tuple>
void print_helper(std::ostream& s, const Tuple& t, std::index_sequence<Is...>)
{
int dummy[] = { 0, ((s << std::get<Is>(t) << ", "), 0)...};
(void) dummy; // remove warning for unused var
}
template<typename Tuple>
void print(std::ostream& s, const Tuple& t)
{
print_helper(s, t, std::make_index_sequence<std::tuple_size<Tuple>::value>());
}
Live example