Fold expression with comma operator and variadic template parameter pack










11















#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?










share|improve this question



















  • 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











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
















11















#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?










share|improve this question



















  • 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











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














11












11








11


2






#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?










share|improve this question
















#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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








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






  • 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













  • 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











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








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













2 Answers
2






active

oldest

votes


















6














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';





share|improve this answer























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







  • 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



















4














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.






share|improve this answer




















  • 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











  • @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











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
);



);













draft saved

draft discarded


















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









6














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';





share|improve this answer























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







  • 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
















6














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';





share|improve this answer























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







  • 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














6












6








6







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';





share|improve this answer













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';






share|improve this answer












share|improve this answer



share|improve this answer










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







  • 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


















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







  • 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

















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














4














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.






share|improve this answer




















  • 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











  • @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
















4














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.






share|improve this answer




















  • 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











  • @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














4












4








4







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.






share|improve this answer















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.







share|improve this answer














share|improve this answer



share|improve this answer








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













  • 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











  • @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








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


















draft saved

draft discarded
















































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.




draft saved


draft discarded














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





















































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







Popular posts from this blog

Top Tejano songwriter Luis Silva dead of heart attack at 64

ReactJS Fetched API data displays live - need Data displayed static

Evgeni Malkin