Is it possible to insert extra operation in fold expression?
up vote
8
down vote
favorite
In C++17, fold expression is available, so to print arguments, we could use
template<typename ...Args>
void output_argus(Args&&... args)
{
(cout << ... << args) << EOL;
}
int main()
{
output_argus(1, "test", 5.6f);
}
having the output1test5.6
What if I would like using the fold expression appending an extra character 'n'
to each element to get the following results?
1
test
5.6
Is that even possible? If yes, how?
c++ templates c++17 variadic-templates fold-expression
add a comment |
up vote
8
down vote
favorite
In C++17, fold expression is available, so to print arguments, we could use
template<typename ...Args>
void output_argus(Args&&... args)
{
(cout << ... << args) << EOL;
}
int main()
{
output_argus(1, "test", 5.6f);
}
having the output1test5.6
What if I would like using the fold expression appending an extra character 'n'
to each element to get the following results?
1
test
5.6
Is that even possible? If yes, how?
c++ templates c++17 variadic-templates fold-expression
add a comment |
up vote
8
down vote
favorite
up vote
8
down vote
favorite
In C++17, fold expression is available, so to print arguments, we could use
template<typename ...Args>
void output_argus(Args&&... args)
{
(cout << ... << args) << EOL;
}
int main()
{
output_argus(1, "test", 5.6f);
}
having the output1test5.6
What if I would like using the fold expression appending an extra character 'n'
to each element to get the following results?
1
test
5.6
Is that even possible? If yes, how?
c++ templates c++17 variadic-templates fold-expression
In C++17, fold expression is available, so to print arguments, we could use
template<typename ...Args>
void output_argus(Args&&... args)
{
(cout << ... << args) << EOL;
}
int main()
{
output_argus(1, "test", 5.6f);
}
having the output1test5.6
What if I would like using the fold expression appending an extra character 'n'
to each element to get the following results?
1
test
5.6
Is that even possible? If yes, how?
c++ templates c++17 variadic-templates fold-expression
c++ templates c++17 variadic-templates fold-expression
edited Nov 8 at 22:35
max66
32.4k63660
32.4k63660
asked Nov 8 at 22:16
r0ng
625723
625723
add a comment |
add a comment |
3 Answers
3
active
oldest
votes
up vote
12
down vote
accepted
What if I would like using the fold expression appending an extra character 'n' to each element to get the following results?
You can use the power of the comma operator
((std::cout << args << std::endl), ...);
or, as suggested by Quentin (thanks) and as you asked, you can simply use n
instead of std::endl
(to avoid multiple flushing of the stream)
((std::cout << args << 'n'), ...);
3
std::endl
is completely overkill, OP just wants a newline.
– Quentin
Nov 8 at 22:31
@Quentin - good point; added to the answer.
– max66
Nov 8 at 22:34
add a comment |
up vote
2
down vote
This is @n.m.'s solution without the rude global greedy operator<<
.
template<class Os>
struct chain_stream {
Os& stream;
template<class Rhs,
std::enable_if_t<std::is_same_v<Os&, decltype(std::declval<Os&>() << std::declval<Rhs>())>, bool> =true
>
friend chain_stream<Os> const& operator<<( chain_stream<Os> const& os, Rhs&& rhs ) {
os.stream << std::forward<Rhs>(rhs);
return os;
}
// iomanipulator:
friend chain_stream<Os> const& operator<<( chain_stream<Os> const& os, Os&(*rhs)(Os&) ) {
os.stream << rhs;
return os;
}
template<class Rhs,
std::enable_if_t<
std::is_same_v< std::result_of_t< Rhs&&(chain_stream const&) >, void >
|| std::is_same_v< std::result_of_t< Rhs&&(chain_stream const&) >, Os& >,
bool> =true
>
friend chain_stream<Os> const& operator<<( chain_stream<Os> const& os, Rhs&& rhs ) {
std::forward<Rhs>(rhs)( os );
return os;
}
};
now we can do:
(chain_stream{std::cout} << ... << [&](auto& x){x << args << 'n';});
and it works.
add a comment |
up vote
1
down vote
I know that the comma operator is probably the easiest way to do that, but for completeness here's something I came up with, mainly because I wanted to show off my little generalisation of iomanip. The standard library iomanips are functions. There's an <<
overload that takes a function pointer. I extended that for arbitrary callable objects that take and return streams by reference.
template <class Stream, class Func>
auto operator << (Stream& s, Func f) ->
std::enable_if_t<std::is_same_v<decltype(f(s)), Stream&>, Stream&>
{
return f(s);
}
With this little tool in our toolbox, it's easy to write a fold expression that does absolutely anything we want.
template<typename ...Args>
void output_args(Args&&... args)
{
(std::cout << ... << [&](auto& x)->auto&{return x << args << 'n';});
}
This technique can be used in scenarios where we need to capture the value of the fold expression, rather than its side effects. The comma operator is less useful in such contexts.
A free greedy<<
operator seems rude. Instead, I'd tag one of the types (the function or the stream).
– Yakk - Adam Nevraumont
Nov 9 at 0:54
See my solution based off yours.
– Yakk - Adam Nevraumont
Nov 9 at 1:07
@Yakk-AdamNevraumont the idea is to have function objects working exactly like plain old functions. Plain old functions are already working as io manipulators.
– n.m.
Nov 9 at 5:43
yes, but the<<
overload for them has specific types. Yours will work on things itterly unrelates to ostreams. Possibly by accident, in the worst case cause build breaks due to non-sfinae errors.
– Yakk - Adam Nevraumont
Nov 9 at 12:20
@Yakk-AdamNevraumont Yes, it is easy to restrict this to ostreams, didn't do this here to reduce verbosity.
– n.m.
Nov 9 at 13:10
add a comment |
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
12
down vote
accepted
What if I would like using the fold expression appending an extra character 'n' to each element to get the following results?
You can use the power of the comma operator
((std::cout << args << std::endl), ...);
or, as suggested by Quentin (thanks) and as you asked, you can simply use n
instead of std::endl
(to avoid multiple flushing of the stream)
((std::cout << args << 'n'), ...);
3
std::endl
is completely overkill, OP just wants a newline.
– Quentin
Nov 8 at 22:31
@Quentin - good point; added to the answer.
– max66
Nov 8 at 22:34
add a comment |
up vote
12
down vote
accepted
What if I would like using the fold expression appending an extra character 'n' to each element to get the following results?
You can use the power of the comma operator
((std::cout << args << std::endl), ...);
or, as suggested by Quentin (thanks) and as you asked, you can simply use n
instead of std::endl
(to avoid multiple flushing of the stream)
((std::cout << args << 'n'), ...);
3
std::endl
is completely overkill, OP just wants a newline.
– Quentin
Nov 8 at 22:31
@Quentin - good point; added to the answer.
– max66
Nov 8 at 22:34
add a comment |
up vote
12
down vote
accepted
up vote
12
down vote
accepted
What if I would like using the fold expression appending an extra character 'n' to each element to get the following results?
You can use the power of the comma operator
((std::cout << args << std::endl), ...);
or, as suggested by Quentin (thanks) and as you asked, you can simply use n
instead of std::endl
(to avoid multiple flushing of the stream)
((std::cout << args << 'n'), ...);
What if I would like using the fold expression appending an extra character 'n' to each element to get the following results?
You can use the power of the comma operator
((std::cout << args << std::endl), ...);
or, as suggested by Quentin (thanks) and as you asked, you can simply use n
instead of std::endl
(to avoid multiple flushing of the stream)
((std::cout << args << 'n'), ...);
edited Nov 8 at 22:34
answered Nov 8 at 22:28
max66
32.4k63660
32.4k63660
3
std::endl
is completely overkill, OP just wants a newline.
– Quentin
Nov 8 at 22:31
@Quentin - good point; added to the answer.
– max66
Nov 8 at 22:34
add a comment |
3
std::endl
is completely overkill, OP just wants a newline.
– Quentin
Nov 8 at 22:31
@Quentin - good point; added to the answer.
– max66
Nov 8 at 22:34
3
3
std::endl
is completely overkill, OP just wants a newline.– Quentin
Nov 8 at 22:31
std::endl
is completely overkill, OP just wants a newline.– Quentin
Nov 8 at 22:31
@Quentin - good point; added to the answer.
– max66
Nov 8 at 22:34
@Quentin - good point; added to the answer.
– max66
Nov 8 at 22:34
add a comment |
up vote
2
down vote
This is @n.m.'s solution without the rude global greedy operator<<
.
template<class Os>
struct chain_stream {
Os& stream;
template<class Rhs,
std::enable_if_t<std::is_same_v<Os&, decltype(std::declval<Os&>() << std::declval<Rhs>())>, bool> =true
>
friend chain_stream<Os> const& operator<<( chain_stream<Os> const& os, Rhs&& rhs ) {
os.stream << std::forward<Rhs>(rhs);
return os;
}
// iomanipulator:
friend chain_stream<Os> const& operator<<( chain_stream<Os> const& os, Os&(*rhs)(Os&) ) {
os.stream << rhs;
return os;
}
template<class Rhs,
std::enable_if_t<
std::is_same_v< std::result_of_t< Rhs&&(chain_stream const&) >, void >
|| std::is_same_v< std::result_of_t< Rhs&&(chain_stream const&) >, Os& >,
bool> =true
>
friend chain_stream<Os> const& operator<<( chain_stream<Os> const& os, Rhs&& rhs ) {
std::forward<Rhs>(rhs)( os );
return os;
}
};
now we can do:
(chain_stream{std::cout} << ... << [&](auto& x){x << args << 'n';});
and it works.
add a comment |
up vote
2
down vote
This is @n.m.'s solution without the rude global greedy operator<<
.
template<class Os>
struct chain_stream {
Os& stream;
template<class Rhs,
std::enable_if_t<std::is_same_v<Os&, decltype(std::declval<Os&>() << std::declval<Rhs>())>, bool> =true
>
friend chain_stream<Os> const& operator<<( chain_stream<Os> const& os, Rhs&& rhs ) {
os.stream << std::forward<Rhs>(rhs);
return os;
}
// iomanipulator:
friend chain_stream<Os> const& operator<<( chain_stream<Os> const& os, Os&(*rhs)(Os&) ) {
os.stream << rhs;
return os;
}
template<class Rhs,
std::enable_if_t<
std::is_same_v< std::result_of_t< Rhs&&(chain_stream const&) >, void >
|| std::is_same_v< std::result_of_t< Rhs&&(chain_stream const&) >, Os& >,
bool> =true
>
friend chain_stream<Os> const& operator<<( chain_stream<Os> const& os, Rhs&& rhs ) {
std::forward<Rhs>(rhs)( os );
return os;
}
};
now we can do:
(chain_stream{std::cout} << ... << [&](auto& x){x << args << 'n';});
and it works.
add a comment |
up vote
2
down vote
up vote
2
down vote
This is @n.m.'s solution without the rude global greedy operator<<
.
template<class Os>
struct chain_stream {
Os& stream;
template<class Rhs,
std::enable_if_t<std::is_same_v<Os&, decltype(std::declval<Os&>() << std::declval<Rhs>())>, bool> =true
>
friend chain_stream<Os> const& operator<<( chain_stream<Os> const& os, Rhs&& rhs ) {
os.stream << std::forward<Rhs>(rhs);
return os;
}
// iomanipulator:
friend chain_stream<Os> const& operator<<( chain_stream<Os> const& os, Os&(*rhs)(Os&) ) {
os.stream << rhs;
return os;
}
template<class Rhs,
std::enable_if_t<
std::is_same_v< std::result_of_t< Rhs&&(chain_stream const&) >, void >
|| std::is_same_v< std::result_of_t< Rhs&&(chain_stream const&) >, Os& >,
bool> =true
>
friend chain_stream<Os> const& operator<<( chain_stream<Os> const& os, Rhs&& rhs ) {
std::forward<Rhs>(rhs)( os );
return os;
}
};
now we can do:
(chain_stream{std::cout} << ... << [&](auto& x){x << args << 'n';});
and it works.
This is @n.m.'s solution without the rude global greedy operator<<
.
template<class Os>
struct chain_stream {
Os& stream;
template<class Rhs,
std::enable_if_t<std::is_same_v<Os&, decltype(std::declval<Os&>() << std::declval<Rhs>())>, bool> =true
>
friend chain_stream<Os> const& operator<<( chain_stream<Os> const& os, Rhs&& rhs ) {
os.stream << std::forward<Rhs>(rhs);
return os;
}
// iomanipulator:
friend chain_stream<Os> const& operator<<( chain_stream<Os> const& os, Os&(*rhs)(Os&) ) {
os.stream << rhs;
return os;
}
template<class Rhs,
std::enable_if_t<
std::is_same_v< std::result_of_t< Rhs&&(chain_stream const&) >, void >
|| std::is_same_v< std::result_of_t< Rhs&&(chain_stream const&) >, Os& >,
bool> =true
>
friend chain_stream<Os> const& operator<<( chain_stream<Os> const& os, Rhs&& rhs ) {
std::forward<Rhs>(rhs)( os );
return os;
}
};
now we can do:
(chain_stream{std::cout} << ... << [&](auto& x){x << args << 'n';});
and it works.
answered Nov 9 at 1:07
Yakk - Adam Nevraumont
178k19185364
178k19185364
add a comment |
add a comment |
up vote
1
down vote
I know that the comma operator is probably the easiest way to do that, but for completeness here's something I came up with, mainly because I wanted to show off my little generalisation of iomanip. The standard library iomanips are functions. There's an <<
overload that takes a function pointer. I extended that for arbitrary callable objects that take and return streams by reference.
template <class Stream, class Func>
auto operator << (Stream& s, Func f) ->
std::enable_if_t<std::is_same_v<decltype(f(s)), Stream&>, Stream&>
{
return f(s);
}
With this little tool in our toolbox, it's easy to write a fold expression that does absolutely anything we want.
template<typename ...Args>
void output_args(Args&&... args)
{
(std::cout << ... << [&](auto& x)->auto&{return x << args << 'n';});
}
This technique can be used in scenarios where we need to capture the value of the fold expression, rather than its side effects. The comma operator is less useful in such contexts.
A free greedy<<
operator seems rude. Instead, I'd tag one of the types (the function or the stream).
– Yakk - Adam Nevraumont
Nov 9 at 0:54
See my solution based off yours.
– Yakk - Adam Nevraumont
Nov 9 at 1:07
@Yakk-AdamNevraumont the idea is to have function objects working exactly like plain old functions. Plain old functions are already working as io manipulators.
– n.m.
Nov 9 at 5:43
yes, but the<<
overload for them has specific types. Yours will work on things itterly unrelates to ostreams. Possibly by accident, in the worst case cause build breaks due to non-sfinae errors.
– Yakk - Adam Nevraumont
Nov 9 at 12:20
@Yakk-AdamNevraumont Yes, it is easy to restrict this to ostreams, didn't do this here to reduce verbosity.
– n.m.
Nov 9 at 13:10
add a comment |
up vote
1
down vote
I know that the comma operator is probably the easiest way to do that, but for completeness here's something I came up with, mainly because I wanted to show off my little generalisation of iomanip. The standard library iomanips are functions. There's an <<
overload that takes a function pointer. I extended that for arbitrary callable objects that take and return streams by reference.
template <class Stream, class Func>
auto operator << (Stream& s, Func f) ->
std::enable_if_t<std::is_same_v<decltype(f(s)), Stream&>, Stream&>
{
return f(s);
}
With this little tool in our toolbox, it's easy to write a fold expression that does absolutely anything we want.
template<typename ...Args>
void output_args(Args&&... args)
{
(std::cout << ... << [&](auto& x)->auto&{return x << args << 'n';});
}
This technique can be used in scenarios where we need to capture the value of the fold expression, rather than its side effects. The comma operator is less useful in such contexts.
A free greedy<<
operator seems rude. Instead, I'd tag one of the types (the function or the stream).
– Yakk - Adam Nevraumont
Nov 9 at 0:54
See my solution based off yours.
– Yakk - Adam Nevraumont
Nov 9 at 1:07
@Yakk-AdamNevraumont the idea is to have function objects working exactly like plain old functions. Plain old functions are already working as io manipulators.
– n.m.
Nov 9 at 5:43
yes, but the<<
overload for them has specific types. Yours will work on things itterly unrelates to ostreams. Possibly by accident, in the worst case cause build breaks due to non-sfinae errors.
– Yakk - Adam Nevraumont
Nov 9 at 12:20
@Yakk-AdamNevraumont Yes, it is easy to restrict this to ostreams, didn't do this here to reduce verbosity.
– n.m.
Nov 9 at 13:10
add a comment |
up vote
1
down vote
up vote
1
down vote
I know that the comma operator is probably the easiest way to do that, but for completeness here's something I came up with, mainly because I wanted to show off my little generalisation of iomanip. The standard library iomanips are functions. There's an <<
overload that takes a function pointer. I extended that for arbitrary callable objects that take and return streams by reference.
template <class Stream, class Func>
auto operator << (Stream& s, Func f) ->
std::enable_if_t<std::is_same_v<decltype(f(s)), Stream&>, Stream&>
{
return f(s);
}
With this little tool in our toolbox, it's easy to write a fold expression that does absolutely anything we want.
template<typename ...Args>
void output_args(Args&&... args)
{
(std::cout << ... << [&](auto& x)->auto&{return x << args << 'n';});
}
This technique can be used in scenarios where we need to capture the value of the fold expression, rather than its side effects. The comma operator is less useful in such contexts.
I know that the comma operator is probably the easiest way to do that, but for completeness here's something I came up with, mainly because I wanted to show off my little generalisation of iomanip. The standard library iomanips are functions. There's an <<
overload that takes a function pointer. I extended that for arbitrary callable objects that take and return streams by reference.
template <class Stream, class Func>
auto operator << (Stream& s, Func f) ->
std::enable_if_t<std::is_same_v<decltype(f(s)), Stream&>, Stream&>
{
return f(s);
}
With this little tool in our toolbox, it's easy to write a fold expression that does absolutely anything we want.
template<typename ...Args>
void output_args(Args&&... args)
{
(std::cout << ... << [&](auto& x)->auto&{return x << args << 'n';});
}
This technique can be used in scenarios where we need to capture the value of the fold expression, rather than its side effects. The comma operator is less useful in such contexts.
answered Nov 8 at 23:09
n.m.
69.8k882165
69.8k882165
A free greedy<<
operator seems rude. Instead, I'd tag one of the types (the function or the stream).
– Yakk - Adam Nevraumont
Nov 9 at 0:54
See my solution based off yours.
– Yakk - Adam Nevraumont
Nov 9 at 1:07
@Yakk-AdamNevraumont the idea is to have function objects working exactly like plain old functions. Plain old functions are already working as io manipulators.
– n.m.
Nov 9 at 5:43
yes, but the<<
overload for them has specific types. Yours will work on things itterly unrelates to ostreams. Possibly by accident, in the worst case cause build breaks due to non-sfinae errors.
– Yakk - Adam Nevraumont
Nov 9 at 12:20
@Yakk-AdamNevraumont Yes, it is easy to restrict this to ostreams, didn't do this here to reduce verbosity.
– n.m.
Nov 9 at 13:10
add a comment |
A free greedy<<
operator seems rude. Instead, I'd tag one of the types (the function or the stream).
– Yakk - Adam Nevraumont
Nov 9 at 0:54
See my solution based off yours.
– Yakk - Adam Nevraumont
Nov 9 at 1:07
@Yakk-AdamNevraumont the idea is to have function objects working exactly like plain old functions. Plain old functions are already working as io manipulators.
– n.m.
Nov 9 at 5:43
yes, but the<<
overload for them has specific types. Yours will work on things itterly unrelates to ostreams. Possibly by accident, in the worst case cause build breaks due to non-sfinae errors.
– Yakk - Adam Nevraumont
Nov 9 at 12:20
@Yakk-AdamNevraumont Yes, it is easy to restrict this to ostreams, didn't do this here to reduce verbosity.
– n.m.
Nov 9 at 13:10
A free greedy
<<
operator seems rude. Instead, I'd tag one of the types (the function or the stream).– Yakk - Adam Nevraumont
Nov 9 at 0:54
A free greedy
<<
operator seems rude. Instead, I'd tag one of the types (the function or the stream).– Yakk - Adam Nevraumont
Nov 9 at 0:54
See my solution based off yours.
– Yakk - Adam Nevraumont
Nov 9 at 1:07
See my solution based off yours.
– Yakk - Adam Nevraumont
Nov 9 at 1:07
@Yakk-AdamNevraumont the idea is to have function objects working exactly like plain old functions. Plain old functions are already working as io manipulators.
– n.m.
Nov 9 at 5:43
@Yakk-AdamNevraumont the idea is to have function objects working exactly like plain old functions. Plain old functions are already working as io manipulators.
– n.m.
Nov 9 at 5:43
yes, but the
<<
overload for them has specific types. Yours will work on things itterly unrelates to ostreams. Possibly by accident, in the worst case cause build breaks due to non-sfinae errors.– Yakk - Adam Nevraumont
Nov 9 at 12:20
yes, but the
<<
overload for them has specific types. Yours will work on things itterly unrelates to ostreams. Possibly by accident, in the worst case cause build breaks due to non-sfinae errors.– Yakk - Adam Nevraumont
Nov 9 at 12:20
@Yakk-AdamNevraumont Yes, it is easy to restrict this to ostreams, didn't do this here to reduce verbosity.
– n.m.
Nov 9 at 13:10
@Yakk-AdamNevraumont Yes, it is easy to restrict this to ostreams, didn't do this here to reduce verbosity.
– n.m.
Nov 9 at 13:10
add a comment |
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53216992%2fis-it-possible-to-insert-extra-operation-in-fold-expression%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown