Fold expression with comma operator and variadic template parameter pack
#include<iostream>
using namespace std;
template<typename ...Args>
void output_argus(Args&&... args)
((cout << args << 'n'), ...); // #1
(... , (cout << args << 'n')); // #2
int main()
output_argus(1, "test", 5.6f);
Based on c++ operator doc, ','
is a left to right operator. It is meaning a, b, c, d
meaning (((a, b), c),d)
not (a, (b, (c, d)))
. This is important if a, b, c, d are statements.
However, based on fold expression doc, for ','
which should use unary left fold.
My question why both statements in my code are working? Shouldn't only #2 work?
And also how to understand ...
and args
. and nested fold expression?
c++ c++17 variadic-templates operator-keyword fold
add a comment |
#include<iostream>
using namespace std;
template<typename ...Args>
void output_argus(Args&&... args)
((cout << args << 'n'), ...); // #1
(... , (cout << args << 'n')); // #2
int main()
output_argus(1, "test", 5.6f);
Based on c++ operator doc, ','
is a left to right operator. It is meaning a, b, c, d
meaning (((a, b), c),d)
not (a, (b, (c, d)))
. This is important if a, b, c, d are statements.
However, based on fold expression doc, for ','
which should use unary left fold.
My question why both statements in my code are working? Shouldn't only #2 work?
And also how to understand ...
and args
. and nested fold expression?
c++ c++17 variadic-templates operator-keyword fold
1
I dont understand how(((a, b), c),d)
and(a, (b, (c, d)))
are different... the first element is evaluated then discarded... so any way do you do ita
will be evaluated then discarded,b
will be evaluated then discarded,c
will be evaluated then discarded, ...
– Grady Player
Nov 16 '18 at 2:57
Left and right fold often do the same thing, despite seeming opposite.
– Yakk - Adam Nevraumont
Nov 16 '18 at 3:06
1
(((a, b), c),d)
is exactly the same as(a, (b, (c, d)))
. The sequencing is a -> b -> c -> d, and the result isd
. Actually this might be a good example to understand for people unsure about the difference between precedence and order of evaluation
– M.M
Nov 16 '18 at 3:35
add a comment |
#include<iostream>
using namespace std;
template<typename ...Args>
void output_argus(Args&&... args)
((cout << args << 'n'), ...); // #1
(... , (cout << args << 'n')); // #2
int main()
output_argus(1, "test", 5.6f);
Based on c++ operator doc, ','
is a left to right operator. It is meaning a, b, c, d
meaning (((a, b), c),d)
not (a, (b, (c, d)))
. This is important if a, b, c, d are statements.
However, based on fold expression doc, for ','
which should use unary left fold.
My question why both statements in my code are working? Shouldn't only #2 work?
And also how to understand ...
and args
. and nested fold expression?
c++ c++17 variadic-templates operator-keyword fold
#include<iostream>
using namespace std;
template<typename ...Args>
void output_argus(Args&&... args)
((cout << args << 'n'), ...); // #1
(... , (cout << args << 'n')); // #2
int main()
output_argus(1, "test", 5.6f);
Based on c++ operator doc, ','
is a left to right operator. It is meaning a, b, c, d
meaning (((a, b), c),d)
not (a, (b, (c, d)))
. This is important if a, b, c, d are statements.
However, based on fold expression doc, for ','
which should use unary left fold.
My question why both statements in my code are working? Shouldn't only #2 work?
And also how to understand ...
and args
. and nested fold expression?
c++ c++17 variadic-templates operator-keyword fold
c++ c++17 variadic-templates operator-keyword fold
edited Nov 16 '18 at 4:50
Barry
185k21325598
185k21325598
asked Nov 16 '18 at 2:48
Ke ZhangKe Zhang
535
535
1
I dont understand how(((a, b), c),d)
and(a, (b, (c, d)))
are different... the first element is evaluated then discarded... so any way do you do ita
will be evaluated then discarded,b
will be evaluated then discarded,c
will be evaluated then discarded, ...
– Grady Player
Nov 16 '18 at 2:57
Left and right fold often do the same thing, despite seeming opposite.
– Yakk - Adam Nevraumont
Nov 16 '18 at 3:06
1
(((a, b), c),d)
is exactly the same as(a, (b, (c, d)))
. The sequencing is a -> b -> c -> d, and the result isd
. Actually this might be a good example to understand for people unsure about the difference between precedence and order of evaluation
– M.M
Nov 16 '18 at 3:35
add a comment |
1
I dont understand how(((a, b), c),d)
and(a, (b, (c, d)))
are different... the first element is evaluated then discarded... so any way do you do ita
will be evaluated then discarded,b
will be evaluated then discarded,c
will be evaluated then discarded, ...
– Grady Player
Nov 16 '18 at 2:57
Left and right fold often do the same thing, despite seeming opposite.
– Yakk - Adam Nevraumont
Nov 16 '18 at 3:06
1
(((a, b), c),d)
is exactly the same as(a, (b, (c, d)))
. The sequencing is a -> b -> c -> d, and the result isd
. Actually this might be a good example to understand for people unsure about the difference between precedence and order of evaluation
– M.M
Nov 16 '18 at 3:35
1
1
I dont understand how
(((a, b), c),d)
and (a, (b, (c, d)))
are different... the first element is evaluated then discarded... so any way do you do it a
will be evaluated then discarded, b
will be evaluated then discarded, c
will be evaluated then discarded, ...– Grady Player
Nov 16 '18 at 2:57
I dont understand how
(((a, b), c),d)
and (a, (b, (c, d)))
are different... the first element is evaluated then discarded... so any way do you do it a
will be evaluated then discarded, b
will be evaluated then discarded, c
will be evaluated then discarded, ...– Grady Player
Nov 16 '18 at 2:57
Left and right fold often do the same thing, despite seeming opposite.
– Yakk - Adam Nevraumont
Nov 16 '18 at 3:06
Left and right fold often do the same thing, despite seeming opposite.
– Yakk - Adam Nevraumont
Nov 16 '18 at 3:06
1
1
(((a, b), c),d)
is exactly the same as (a, (b, (c, d)))
. The sequencing is a -> b -> c -> d, and the result is d
. Actually this might be a good example to understand for people unsure about the difference between precedence and order of evaluation– M.M
Nov 16 '18 at 3:35
(((a, b), c),d)
is exactly the same as (a, (b, (c, d)))
. The sequencing is a -> b -> c -> d, and the result is d
. Actually this might be a good example to understand for people unsure about the difference between precedence and order of evaluation– M.M
Nov 16 '18 at 3:35
add a comment |
2 Answers
2
active
oldest
votes
Let's say we're folding 3 expressions over a binary operator, with a unary fold. We have two options here: (xs @ ...)
(a unary right fold) and (... @ xs)
(a unary left fold).
(xs @ ...)
expands out to (a @ (b @ c))
(... @ xs)
expands out to ((a @ b) @ c)
What can we say about the difference between the expressions a @ (b @ c)
and (a @ b) @ c
? If @
is associative over these types, then those two expressions are identical. That's what associative means. If you had a parameter pack of integers, then a unary left fold over +
and a unary right fold over +
will have the same value (modulo overflow), because addition is associative. Subtraction, on the other hand, is not associative. (xs - ...)
and (... - xs)
mean very different things.
Likewise, the ,
operator in C++ is associative. It doesn't matter which way you parenthesize the expressions. ((a, b), c)
and (a, (b, c))
both evaluate and discard a
, then evaluate and discard b
, then evaluate c
and that's the result. It's easier to see if you reduce the expressions to just letters why this is the case.
As a result, both ((cout << args << 'n'), ...)
and (... , (cout << args << 'n'))
do the same thing, and they both effectively mean:
cout << args1 << 'n';
cout << args2 << 'n';
// ...
cout << argsN << 'n';
Thanks for your answer. It gives me new thinking about comma and parentheses. It turns out a @ (b @ c) won't lead to execute b first which is true in cpp and false in mathematic field. The doc's academic style makes me feel it's expand in a logic way.
– Ke Zhang
Nov 16 '18 at 6:23
1
@KeZhang, It shouldn't matter which of a/b/c you evaluate ("execute") first in math. The parentheses affect the precedence, which means you need to calculateb @ c
before calculatinga @ (b @ c)
, but that's also true of C++. Unlike C++, math doesn't have things with side effects like prints, and that's where C++ needs to consider evaluation order beyond simple precedence and associativity rules.
– chris
Nov 16 '18 at 9:05
@chris , about which means you need to calculate b @ c before calculating a @ (b @ c), I have different opinion and I post a new question here.
– Ke Zhang
Nov 16 '18 at 22:15
1
@KeZhang, Keep in mind when I sayb @ c
needs to be done beforea @ (b @ c)
, that doesn't impose any restrictions ona
,b
, andc
individually. You could evaluatea
, thenb
, thenc
, then the inner@
, then the outer@
. What I meant was that you cannot, for example, evaluate the outer@
before the inner one because the outer one depends on the result of the inner one. Likewise, you can't evaluate the inner@
before evaluatingb
andc
because it depends on those. Apart from dependencies, the order is free reign unless otherwise specified, like the comma operator is.
– chris
Nov 16 '18 at 22:21
add a comment |
From the linked page, your #1 expands as follows:
((cout << args₀ << 'n'), ((cout << args₁ << 'n'), (cout << args₂ << 'n')));
Removing some repetition to make it cleaner:
args₀, (args₁, args₂)
For #2, the expansion boils down to:
(args₀, args₁), args₂
Let's walk through the evaluation of each one.
#1:
args₀ , (args₁, args₂)
^^^
The underlined comma evaluates the left side, printing 1
. Then the right side is evaluated, which evaluates the print of args₁
, printing test
, then the print of args₂
, printing 5.6
.
#2:
(args₀, args₁) , args₂
^^^
The underlined comma evaluates the left side. This triggers evaluation of the other comma, which evaluates the print of args₀
, printing 1
, then evaluates the print of args₁
, printing test
. Now the underlined comma is done evaluating the left side and evaluates the right side, printing 5.6
.
As you can see, both produce the same evaluation order of each individual argument despite the grouping of parentheses being different.
Note that in general, this might not always hold. Some operators, such as +
, do not have a guaranteed evaluation order like the comma operator does. Were such an operator used instead of the comma to join the print expressions, the compiler could ultimately choose to evaluate the individual argument prints in any order.
1
Streaming with cout may be a better example of difference.(cout << 1)<<2
vscout <<(1 << 2)
.
– Yakk - Adam Nevraumont
Nov 16 '18 at 3:24
@Yakk-AdamNevraumont, While true, I couldn't think of a particularly nice way to fit it in with fold expression explanations. The two options provided are(cout << 1) << 2
and1 << (2 << cout)
, with the need to do some kind of extra building on top if we want to formcout << (1 << 2)
for an example. I guesscout
could be part of the parameter pack to make it work, though, instead of needing the binary fold.
– chris
Nov 16 '18 at 3:32
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
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%2f53330713%2ffold-expression-with-comma-operator-and-variadic-template-parameter-pack%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
Let's say we're folding 3 expressions over a binary operator, with a unary fold. We have two options here: (xs @ ...)
(a unary right fold) and (... @ xs)
(a unary left fold).
(xs @ ...)
expands out to (a @ (b @ c))
(... @ xs)
expands out to ((a @ b) @ c)
What can we say about the difference between the expressions a @ (b @ c)
and (a @ b) @ c
? If @
is associative over these types, then those two expressions are identical. That's what associative means. If you had a parameter pack of integers, then a unary left fold over +
and a unary right fold over +
will have the same value (modulo overflow), because addition is associative. Subtraction, on the other hand, is not associative. (xs - ...)
and (... - xs)
mean very different things.
Likewise, the ,
operator in C++ is associative. It doesn't matter which way you parenthesize the expressions. ((a, b), c)
and (a, (b, c))
both evaluate and discard a
, then evaluate and discard b
, then evaluate c
and that's the result. It's easier to see if you reduce the expressions to just letters why this is the case.
As a result, both ((cout << args << 'n'), ...)
and (... , (cout << args << 'n'))
do the same thing, and they both effectively mean:
cout << args1 << 'n';
cout << args2 << 'n';
// ...
cout << argsN << 'n';
Thanks for your answer. It gives me new thinking about comma and parentheses. It turns out a @ (b @ c) won't lead to execute b first which is true in cpp and false in mathematic field. The doc's academic style makes me feel it's expand in a logic way.
– Ke Zhang
Nov 16 '18 at 6:23
1
@KeZhang, It shouldn't matter which of a/b/c you evaluate ("execute") first in math. The parentheses affect the precedence, which means you need to calculateb @ c
before calculatinga @ (b @ c)
, but that's also true of C++. Unlike C++, math doesn't have things with side effects like prints, and that's where C++ needs to consider evaluation order beyond simple precedence and associativity rules.
– chris
Nov 16 '18 at 9:05
@chris , about which means you need to calculate b @ c before calculating a @ (b @ c), I have different opinion and I post a new question here.
– Ke Zhang
Nov 16 '18 at 22:15
1
@KeZhang, Keep in mind when I sayb @ c
needs to be done beforea @ (b @ c)
, that doesn't impose any restrictions ona
,b
, andc
individually. You could evaluatea
, thenb
, thenc
, then the inner@
, then the outer@
. What I meant was that you cannot, for example, evaluate the outer@
before the inner one because the outer one depends on the result of the inner one. Likewise, you can't evaluate the inner@
before evaluatingb
andc
because it depends on those. Apart from dependencies, the order is free reign unless otherwise specified, like the comma operator is.
– chris
Nov 16 '18 at 22:21
add a comment |
Let's say we're folding 3 expressions over a binary operator, with a unary fold. We have two options here: (xs @ ...)
(a unary right fold) and (... @ xs)
(a unary left fold).
(xs @ ...)
expands out to (a @ (b @ c))
(... @ xs)
expands out to ((a @ b) @ c)
What can we say about the difference between the expressions a @ (b @ c)
and (a @ b) @ c
? If @
is associative over these types, then those two expressions are identical. That's what associative means. If you had a parameter pack of integers, then a unary left fold over +
and a unary right fold over +
will have the same value (modulo overflow), because addition is associative. Subtraction, on the other hand, is not associative. (xs - ...)
and (... - xs)
mean very different things.
Likewise, the ,
operator in C++ is associative. It doesn't matter which way you parenthesize the expressions. ((a, b), c)
and (a, (b, c))
both evaluate and discard a
, then evaluate and discard b
, then evaluate c
and that's the result. It's easier to see if you reduce the expressions to just letters why this is the case.
As a result, both ((cout << args << 'n'), ...)
and (... , (cout << args << 'n'))
do the same thing, and they both effectively mean:
cout << args1 << 'n';
cout << args2 << 'n';
// ...
cout << argsN << 'n';
Thanks for your answer. It gives me new thinking about comma and parentheses. It turns out a @ (b @ c) won't lead to execute b first which is true in cpp and false in mathematic field. The doc's academic style makes me feel it's expand in a logic way.
– Ke Zhang
Nov 16 '18 at 6:23
1
@KeZhang, It shouldn't matter which of a/b/c you evaluate ("execute") first in math. The parentheses affect the precedence, which means you need to calculateb @ c
before calculatinga @ (b @ c)
, but that's also true of C++. Unlike C++, math doesn't have things with side effects like prints, and that's where C++ needs to consider evaluation order beyond simple precedence and associativity rules.
– chris
Nov 16 '18 at 9:05
@chris , about which means you need to calculate b @ c before calculating a @ (b @ c), I have different opinion and I post a new question here.
– Ke Zhang
Nov 16 '18 at 22:15
1
@KeZhang, Keep in mind when I sayb @ c
needs to be done beforea @ (b @ c)
, that doesn't impose any restrictions ona
,b
, andc
individually. You could evaluatea
, thenb
, thenc
, then the inner@
, then the outer@
. What I meant was that you cannot, for example, evaluate the outer@
before the inner one because the outer one depends on the result of the inner one. Likewise, you can't evaluate the inner@
before evaluatingb
andc
because it depends on those. Apart from dependencies, the order is free reign unless otherwise specified, like the comma operator is.
– chris
Nov 16 '18 at 22:21
add a comment |
Let's say we're folding 3 expressions over a binary operator, with a unary fold. We have two options here: (xs @ ...)
(a unary right fold) and (... @ xs)
(a unary left fold).
(xs @ ...)
expands out to (a @ (b @ c))
(... @ xs)
expands out to ((a @ b) @ c)
What can we say about the difference between the expressions a @ (b @ c)
and (a @ b) @ c
? If @
is associative over these types, then those two expressions are identical. That's what associative means. If you had a parameter pack of integers, then a unary left fold over +
and a unary right fold over +
will have the same value (modulo overflow), because addition is associative. Subtraction, on the other hand, is not associative. (xs - ...)
and (... - xs)
mean very different things.
Likewise, the ,
operator in C++ is associative. It doesn't matter which way you parenthesize the expressions. ((a, b), c)
and (a, (b, c))
both evaluate and discard a
, then evaluate and discard b
, then evaluate c
and that's the result. It's easier to see if you reduce the expressions to just letters why this is the case.
As a result, both ((cout << args << 'n'), ...)
and (... , (cout << args << 'n'))
do the same thing, and they both effectively mean:
cout << args1 << 'n';
cout << args2 << 'n';
// ...
cout << argsN << 'n';
Let's say we're folding 3 expressions over a binary operator, with a unary fold. We have two options here: (xs @ ...)
(a unary right fold) and (... @ xs)
(a unary left fold).
(xs @ ...)
expands out to (a @ (b @ c))
(... @ xs)
expands out to ((a @ b) @ c)
What can we say about the difference between the expressions a @ (b @ c)
and (a @ b) @ c
? If @
is associative over these types, then those two expressions are identical. That's what associative means. If you had a parameter pack of integers, then a unary left fold over +
and a unary right fold over +
will have the same value (modulo overflow), because addition is associative. Subtraction, on the other hand, is not associative. (xs - ...)
and (... - xs)
mean very different things.
Likewise, the ,
operator in C++ is associative. It doesn't matter which way you parenthesize the expressions. ((a, b), c)
and (a, (b, c))
both evaluate and discard a
, then evaluate and discard b
, then evaluate c
and that's the result. It's easier to see if you reduce the expressions to just letters why this is the case.
As a result, both ((cout << args << 'n'), ...)
and (... , (cout << args << 'n'))
do the same thing, and they both effectively mean:
cout << args1 << 'n';
cout << args2 << 'n';
// ...
cout << argsN << 'n';
answered Nov 16 '18 at 4:49
BarryBarry
185k21325598
185k21325598
Thanks for your answer. It gives me new thinking about comma and parentheses. It turns out a @ (b @ c) won't lead to execute b first which is true in cpp and false in mathematic field. The doc's academic style makes me feel it's expand in a logic way.
– Ke Zhang
Nov 16 '18 at 6:23
1
@KeZhang, It shouldn't matter which of a/b/c you evaluate ("execute") first in math. The parentheses affect the precedence, which means you need to calculateb @ c
before calculatinga @ (b @ c)
, but that's also true of C++. Unlike C++, math doesn't have things with side effects like prints, and that's where C++ needs to consider evaluation order beyond simple precedence and associativity rules.
– chris
Nov 16 '18 at 9:05
@chris , about which means you need to calculate b @ c before calculating a @ (b @ c), I have different opinion and I post a new question here.
– Ke Zhang
Nov 16 '18 at 22:15
1
@KeZhang, Keep in mind when I sayb @ c
needs to be done beforea @ (b @ c)
, that doesn't impose any restrictions ona
,b
, andc
individually. You could evaluatea
, thenb
, thenc
, then the inner@
, then the outer@
. What I meant was that you cannot, for example, evaluate the outer@
before the inner one because the outer one depends on the result of the inner one. Likewise, you can't evaluate the inner@
before evaluatingb
andc
because it depends on those. Apart from dependencies, the order is free reign unless otherwise specified, like the comma operator is.
– chris
Nov 16 '18 at 22:21
add a comment |
Thanks for your answer. It gives me new thinking about comma and parentheses. It turns out a @ (b @ c) won't lead to execute b first which is true in cpp and false in mathematic field. The doc's academic style makes me feel it's expand in a logic way.
– Ke Zhang
Nov 16 '18 at 6:23
1
@KeZhang, It shouldn't matter which of a/b/c you evaluate ("execute") first in math. The parentheses affect the precedence, which means you need to calculateb @ c
before calculatinga @ (b @ c)
, but that's also true of C++. Unlike C++, math doesn't have things with side effects like prints, and that's where C++ needs to consider evaluation order beyond simple precedence and associativity rules.
– chris
Nov 16 '18 at 9:05
@chris , about which means you need to calculate b @ c before calculating a @ (b @ c), I have different opinion and I post a new question here.
– Ke Zhang
Nov 16 '18 at 22:15
1
@KeZhang, Keep in mind when I sayb @ c
needs to be done beforea @ (b @ c)
, that doesn't impose any restrictions ona
,b
, andc
individually. You could evaluatea
, thenb
, thenc
, then the inner@
, then the outer@
. What I meant was that you cannot, for example, evaluate the outer@
before the inner one because the outer one depends on the result of the inner one. Likewise, you can't evaluate the inner@
before evaluatingb
andc
because it depends on those. Apart from dependencies, the order is free reign unless otherwise specified, like the comma operator is.
– chris
Nov 16 '18 at 22:21
Thanks for your answer. It gives me new thinking about comma and parentheses. It turns out a @ (b @ c) won't lead to execute b first which is true in cpp and false in mathematic field. The doc's academic style makes me feel it's expand in a logic way.
– Ke Zhang
Nov 16 '18 at 6:23
Thanks for your answer. It gives me new thinking about comma and parentheses. It turns out a @ (b @ c) won't lead to execute b first which is true in cpp and false in mathematic field. The doc's academic style makes me feel it's expand in a logic way.
– Ke Zhang
Nov 16 '18 at 6:23
1
1
@KeZhang, It shouldn't matter which of a/b/c you evaluate ("execute") first in math. The parentheses affect the precedence, which means you need to calculate
b @ c
before calculating a @ (b @ c)
, but that's also true of C++. Unlike C++, math doesn't have things with side effects like prints, and that's where C++ needs to consider evaluation order beyond simple precedence and associativity rules.– chris
Nov 16 '18 at 9:05
@KeZhang, It shouldn't matter which of a/b/c you evaluate ("execute") first in math. The parentheses affect the precedence, which means you need to calculate
b @ c
before calculating a @ (b @ c)
, but that's also true of C++. Unlike C++, math doesn't have things with side effects like prints, and that's where C++ needs to consider evaluation order beyond simple precedence and associativity rules.– chris
Nov 16 '18 at 9:05
@chris , about which means you need to calculate b @ c before calculating a @ (b @ c), I have different opinion and I post a new question here.
– Ke Zhang
Nov 16 '18 at 22:15
@chris , about which means you need to calculate b @ c before calculating a @ (b @ c), I have different opinion and I post a new question here.
– Ke Zhang
Nov 16 '18 at 22:15
1
1
@KeZhang, Keep in mind when I say
b @ c
needs to be done before a @ (b @ c)
, that doesn't impose any restrictions on a
, b
, and c
individually. You could evaluate a
, then b
, then c
, then the inner @
, then the outer @
. What I meant was that you cannot, for example, evaluate the outer @
before the inner one because the outer one depends on the result of the inner one. Likewise, you can't evaluate the inner @
before evaluating b
and c
because it depends on those. Apart from dependencies, the order is free reign unless otherwise specified, like the comma operator is.– chris
Nov 16 '18 at 22:21
@KeZhang, Keep in mind when I say
b @ c
needs to be done before a @ (b @ c)
, that doesn't impose any restrictions on a
, b
, and c
individually. You could evaluate a
, then b
, then c
, then the inner @
, then the outer @
. What I meant was that you cannot, for example, evaluate the outer @
before the inner one because the outer one depends on the result of the inner one. Likewise, you can't evaluate the inner @
before evaluating b
and c
because it depends on those. Apart from dependencies, the order is free reign unless otherwise specified, like the comma operator is.– chris
Nov 16 '18 at 22:21
add a comment |
From the linked page, your #1 expands as follows:
((cout << args₀ << 'n'), ((cout << args₁ << 'n'), (cout << args₂ << 'n')));
Removing some repetition to make it cleaner:
args₀, (args₁, args₂)
For #2, the expansion boils down to:
(args₀, args₁), args₂
Let's walk through the evaluation of each one.
#1:
args₀ , (args₁, args₂)
^^^
The underlined comma evaluates the left side, printing 1
. Then the right side is evaluated, which evaluates the print of args₁
, printing test
, then the print of args₂
, printing 5.6
.
#2:
(args₀, args₁) , args₂
^^^
The underlined comma evaluates the left side. This triggers evaluation of the other comma, which evaluates the print of args₀
, printing 1
, then evaluates the print of args₁
, printing test
. Now the underlined comma is done evaluating the left side and evaluates the right side, printing 5.6
.
As you can see, both produce the same evaluation order of each individual argument despite the grouping of parentheses being different.
Note that in general, this might not always hold. Some operators, such as +
, do not have a guaranteed evaluation order like the comma operator does. Were such an operator used instead of the comma to join the print expressions, the compiler could ultimately choose to evaluate the individual argument prints in any order.
1
Streaming with cout may be a better example of difference.(cout << 1)<<2
vscout <<(1 << 2)
.
– Yakk - Adam Nevraumont
Nov 16 '18 at 3:24
@Yakk-AdamNevraumont, While true, I couldn't think of a particularly nice way to fit it in with fold expression explanations. The two options provided are(cout << 1) << 2
and1 << (2 << cout)
, with the need to do some kind of extra building on top if we want to formcout << (1 << 2)
for an example. I guesscout
could be part of the parameter pack to make it work, though, instead of needing the binary fold.
– chris
Nov 16 '18 at 3:32
add a comment |
From the linked page, your #1 expands as follows:
((cout << args₀ << 'n'), ((cout << args₁ << 'n'), (cout << args₂ << 'n')));
Removing some repetition to make it cleaner:
args₀, (args₁, args₂)
For #2, the expansion boils down to:
(args₀, args₁), args₂
Let's walk through the evaluation of each one.
#1:
args₀ , (args₁, args₂)
^^^
The underlined comma evaluates the left side, printing 1
. Then the right side is evaluated, which evaluates the print of args₁
, printing test
, then the print of args₂
, printing 5.6
.
#2:
(args₀, args₁) , args₂
^^^
The underlined comma evaluates the left side. This triggers evaluation of the other comma, which evaluates the print of args₀
, printing 1
, then evaluates the print of args₁
, printing test
. Now the underlined comma is done evaluating the left side and evaluates the right side, printing 5.6
.
As you can see, both produce the same evaluation order of each individual argument despite the grouping of parentheses being different.
Note that in general, this might not always hold. Some operators, such as +
, do not have a guaranteed evaluation order like the comma operator does. Were such an operator used instead of the comma to join the print expressions, the compiler could ultimately choose to evaluate the individual argument prints in any order.
1
Streaming with cout may be a better example of difference.(cout << 1)<<2
vscout <<(1 << 2)
.
– Yakk - Adam Nevraumont
Nov 16 '18 at 3:24
@Yakk-AdamNevraumont, While true, I couldn't think of a particularly nice way to fit it in with fold expression explanations. The two options provided are(cout << 1) << 2
and1 << (2 << cout)
, with the need to do some kind of extra building on top if we want to formcout << (1 << 2)
for an example. I guesscout
could be part of the parameter pack to make it work, though, instead of needing the binary fold.
– chris
Nov 16 '18 at 3:32
add a comment |
From the linked page, your #1 expands as follows:
((cout << args₀ << 'n'), ((cout << args₁ << 'n'), (cout << args₂ << 'n')));
Removing some repetition to make it cleaner:
args₀, (args₁, args₂)
For #2, the expansion boils down to:
(args₀, args₁), args₂
Let's walk through the evaluation of each one.
#1:
args₀ , (args₁, args₂)
^^^
The underlined comma evaluates the left side, printing 1
. Then the right side is evaluated, which evaluates the print of args₁
, printing test
, then the print of args₂
, printing 5.6
.
#2:
(args₀, args₁) , args₂
^^^
The underlined comma evaluates the left side. This triggers evaluation of the other comma, which evaluates the print of args₀
, printing 1
, then evaluates the print of args₁
, printing test
. Now the underlined comma is done evaluating the left side and evaluates the right side, printing 5.6
.
As you can see, both produce the same evaluation order of each individual argument despite the grouping of parentheses being different.
Note that in general, this might not always hold. Some operators, such as +
, do not have a guaranteed evaluation order like the comma operator does. Were such an operator used instead of the comma to join the print expressions, the compiler could ultimately choose to evaluate the individual argument prints in any order.
From the linked page, your #1 expands as follows:
((cout << args₀ << 'n'), ((cout << args₁ << 'n'), (cout << args₂ << 'n')));
Removing some repetition to make it cleaner:
args₀, (args₁, args₂)
For #2, the expansion boils down to:
(args₀, args₁), args₂
Let's walk through the evaluation of each one.
#1:
args₀ , (args₁, args₂)
^^^
The underlined comma evaluates the left side, printing 1
. Then the right side is evaluated, which evaluates the print of args₁
, printing test
, then the print of args₂
, printing 5.6
.
#2:
(args₀, args₁) , args₂
^^^
The underlined comma evaluates the left side. This triggers evaluation of the other comma, which evaluates the print of args₀
, printing 1
, then evaluates the print of args₁
, printing test
. Now the underlined comma is done evaluating the left side and evaluates the right side, printing 5.6
.
As you can see, both produce the same evaluation order of each individual argument despite the grouping of parentheses being different.
Note that in general, this might not always hold. Some operators, such as +
, do not have a guaranteed evaluation order like the comma operator does. Were such an operator used instead of the comma to join the print expressions, the compiler could ultimately choose to evaluate the individual argument prints in any order.
edited Nov 16 '18 at 3:15
answered Nov 16 '18 at 3:09
chrischris
46.1k9106166
46.1k9106166
1
Streaming with cout may be a better example of difference.(cout << 1)<<2
vscout <<(1 << 2)
.
– Yakk - Adam Nevraumont
Nov 16 '18 at 3:24
@Yakk-AdamNevraumont, While true, I couldn't think of a particularly nice way to fit it in with fold expression explanations. The two options provided are(cout << 1) << 2
and1 << (2 << cout)
, with the need to do some kind of extra building on top if we want to formcout << (1 << 2)
for an example. I guesscout
could be part of the parameter pack to make it work, though, instead of needing the binary fold.
– chris
Nov 16 '18 at 3:32
add a comment |
1
Streaming with cout may be a better example of difference.(cout << 1)<<2
vscout <<(1 << 2)
.
– Yakk - Adam Nevraumont
Nov 16 '18 at 3:24
@Yakk-AdamNevraumont, While true, I couldn't think of a particularly nice way to fit it in with fold expression explanations. The two options provided are(cout << 1) << 2
and1 << (2 << cout)
, with the need to do some kind of extra building on top if we want to formcout << (1 << 2)
for an example. I guesscout
could be part of the parameter pack to make it work, though, instead of needing the binary fold.
– chris
Nov 16 '18 at 3:32
1
1
Streaming with cout may be a better example of difference.
(cout << 1)<<2
vs cout <<(1 << 2)
.– Yakk - Adam Nevraumont
Nov 16 '18 at 3:24
Streaming with cout may be a better example of difference.
(cout << 1)<<2
vs cout <<(1 << 2)
.– Yakk - Adam Nevraumont
Nov 16 '18 at 3:24
@Yakk-AdamNevraumont, While true, I couldn't think of a particularly nice way to fit it in with fold expression explanations. The two options provided are
(cout << 1) << 2
and 1 << (2 << cout)
, with the need to do some kind of extra building on top if we want to form cout << (1 << 2)
for an example. I guess cout
could be part of the parameter pack to make it work, though, instead of needing the binary fold.– chris
Nov 16 '18 at 3:32
@Yakk-AdamNevraumont, While true, I couldn't think of a particularly nice way to fit it in with fold expression explanations. The two options provided are
(cout << 1) << 2
and 1 << (2 << cout)
, with the need to do some kind of extra building on top if we want to form cout << (1 << 2)
for an example. I guess cout
could be part of the parameter pack to make it work, though, instead of needing the binary fold.– chris
Nov 16 '18 at 3:32
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
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%2f53330713%2ffold-expression-with-comma-operator-and-variadic-template-parameter-pack%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
1
I dont understand how
(((a, b), c),d)
and(a, (b, (c, d)))
are different... the first element is evaluated then discarded... so any way do you do ita
will be evaluated then discarded,b
will be evaluated then discarded,c
will be evaluated then discarded, ...– Grady Player
Nov 16 '18 at 2:57
Left and right fold often do the same thing, despite seeming opposite.
– Yakk - Adam Nevraumont
Nov 16 '18 at 3:06
1
(((a, b), c),d)
is exactly the same as(a, (b, (c, d)))
. The sequencing is a -> b -> c -> d, and the result isd
. Actually this might be a good example to understand for people unsure about the difference between precedence and order of evaluation– M.M
Nov 16 '18 at 3:35