What are the evaluation order guarantees introduced by C++17?

前端 未结 3 1223
陌清茗
陌清茗 2020-11-22 01:38

What are the implications of the voted in C++17 evaluation order guarantees (P0145) on typical C++ code?

What does it change about things like the following?



        
3条回答
  •  梦如初夏
    2020-11-22 02:13

    I've found some notes about expression evaluation order:

    • Quick Q: Why doesn’t c++ have a specified order for evaluating function arguments?

      Some order of evaluation guarantees surrounding overloaded operators and complete-argument rules where added in C++17. But it remains that which argument goes first is left unspecified. In C++17, it is now specified that the expression giving what to call (the code on the left of the ( of the function call) goes before the arguments, and whichever argument is evaluated first is evaluated fully before the next one is started, and in the case of an object method the value of the object is evaluated before the arguments to the method are.

    • Order of evaluation

      21) Every expression in a comma-separated list of expressions in a parenthesized initializer is evaluated as if for a function call (indeterminately-sequenced)

    • Ambiguous expressions

      The C++ language does not guarantee the order in which arguments to a function call are evaluated.

    In P0145R3.Refining Expression Evaluation Order for Idiomatic C++ I've found:

    The value computation and associated side-effect of the postfix-expression are sequenced before those of the expressions in the expression-list. The initializations of the declared parameters are indeterminately sequenced with no interleaving.

    But I didn't find it in standard, instead in standard I've found:

    6.8.1.8 Sequential execution [intro.execution] An expression X is said to be sequenced before an expression Y if every value computation and every side effect associated with the expression X is sequenced before every value computation and every side effect associated with the expression Y.

    6.8.1.9 Sequential execution [intro.execution] Every value computation and side effect associated with a full-expression is sequenced before every value computation and side effect associated with the next full-expression to be evaluated.

    7.6.19.1 Comma operator [expr.comma] A pair of expressions separated by a comma is evaluated left-to-right;...

    So, I compared according behavior in three compilers for 14 and 17 standards. The explored code is:

    #include 
    
    struct A
    {
        A& addInt(int i)
        {
            std::cout << "add int: " << i << "\n";
            return *this;
        }
    
        A& addFloat(float i)
        {
            std::cout << "add float: " << i << "\n";
            return *this;
        }
    };
    
    int computeInt()
    {
        std::cout << "compute int\n";
        return 0;
    }
    
    float computeFloat()
    {
        std::cout << "compute float\n";
        return 1.0f;
    }
    
    void compute(float, int)
    {
        std::cout << "compute\n";
    }
    
    int main()
    {
        A a;
        a.addFloat(computeFloat()).addInt(computeInt());
        std::cout << "Function call:\n";
        compute(computeFloat(), computeInt());
    }
    

    Results (the more consistent is clang):

    
    
    C++14 C++17

    gcc 9.0.1
    compute float
    add float: 1
    compute int
    add int: 0
    Function call:
    compute int
    compute float
    compute
    compute float
    add float: 1
    compute int
    add int: 0
    Function call:
    compute int
    compute float
    compute
    clang 9 compute float
    add float: 1
    compute int
    add int: 0
    Function call:
    compute float
    compute int
    compute
    compute float
    add float: 1
    compute int
    add int: 0
    Function call:
    compute float
    compute int
    compute
    msvs 2017 compute int
    compute float
    add float: 1
    add int: 0
    Function call:
    compute int
    compute float
    compute
    compute float
    add float: 1
    compute int
    add int: 0
    Function call:
    compute int
    compute float
    compute

提交回复
热议问题