Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++17: What does "operator with precedence below cast" mean in "fold" concept?

The website of http://en.cppreference.com/w/cpp/language/fold gives an example of how to use fold concept, and it says:

Note
If the expression used as init or as pack has an operator with precedence    
below cast at the top level, it can be parenthesed:

template<typename ...Args>
int sum(Args&&... args) {
//    return (args + ... + 1 * 2); // Error: operator with precedence below cast
    return (args + ... + (1 * 2)); // OK
}

As a non-native English speaker, I don't quit get the sentence:

has an operator with precedence below cast at the top level

What does it actually mean, and it the example, what does it indicate? Could you help to explain this?

Thanks a lot.

like image 778
Hind Forsum Avatar asked Jul 11 '16 03:07

Hind Forsum


People also ask

What is an operator what do you mean by operator precedence?

Operator precedence determines the grouping of terms in an expression and decides how an expression is evaluated. Certain operators have higher precedence than others; for example, the multiplication operator has a higher precedence than the addition operator.

What is the meaning of precedence in C?

The precedence of operators determines which operator is executed first if there is more than one operator in an expression. Let us consider an example: int x = 5 - 17* 6; In C, the precedence of * is higher than - and = . Hence, 17 * 6 is evaluated first.

What is the order of operator precedence?

In the United States and in France, the acronym PEMDAS is common. It stands for Parentheses, Exponents, Multiplication/Division, Addition/Subtraction. PEMDAS is often expanded to the mnemonic "Please Excuse My Dear Aunt Sally" in schools.

What is operator precedence in C Plus Plus?

Operator precedence specifies the order of operations in expressions that contain more than one operator. Operator associativity specifies whether, in an expression that contains multiple operators with the same precedence, an operand is grouped with the one on its left or the one on its right.


2 Answers

The casting operator ((Typename)expr) has a very high precedence in C++'s operator precedence rules. Very few operators have higher precedence than that. Operators of cast level or greater precedence are very special operations, usually applying to a single expression.

In the expression args + ... + 1 * 2, the ... applies to everything both on the left and the right. But what does "on the right" really mean? Does it mean just the + 1 part, or does it mean + 1 * 2?

In the case of operators with high precedence, it's clear what the intent is. For example, args + ... + func(), it's clear that the () function call operator applies to func and not to args + ... + func. It's so unlikely that you would want the latter that you are forced to use parenthesis explicitly if you did ((args + ... + func)()).

However for precedence levels below 3 in the chart, things become much more cloudy for people to understand. So instead of using the normal precedence rules, C++ forces the user to be explicit about it. You can have args + ... + (1 * 2) or (args + ... + 1) * 2. But you have to be clear which one you want.

like image 52
Nicol Bolas Avatar answered Sep 20 '22 15:09

Nicol Bolas


It means that if an expression with several operators is ambiguous, operators that are "above cast" will be called before the cast operator, and operators that are "below cast" will be called after the cast operator. As in 2 + 2 * 2 multiplication should be executed before addition, resulting 6, but not 8.

Let's consider the following two classes which are castable to each other:

class E2;

class E1 {
public:

  operator E2();

  E1 operator++(int) {
    std::cout << "E1 Post-inc\n";
    return *this;
  }

  E1 operator*(const E1&) {
    std::cout << "E1 * E1\n";
    return *this;
  }
};

class E2 {
public:

  operator E1() {
    std::cout << "Cast E1 -> E2\n";
    return E1();
  }

  E2 operator++(int) {
    std::cout << "E2 Post-inc\n";
    return *this;
  }

  E2 operator*(const E2&) {
    std::cout << "E2 * E2\n";
    return *this;
  }
};

E1::operator E2() {
  std::cout << "Cast E2 -> E1\n";
  return E2();
}

Then let's declare

E1 e1;
E2 e2;

and do

(E1)e2++;

Both E1 and E2 have operator ++, so what should be done first in this expression: cast or increment? Precedence table answers that increment should be done first, so the program prints

E2 Post-inc
Cast E1 -> E2

Then, let's try a more complicated example:

e1 * (E1)e2++;

Here we have 3 actions (in order of their appearance in code): multiplication, cast and increment. What thw order if execution will be? Precedence table says that increment is the first, cast is the second (it's below the increment) and multiplication is the last, as it's below both of them. So the output will be:

E2 Post-inc
Cast E1 -> E2
E1 * E1

Note that you can easily reorder the operations using parentheses. For example, if we replace e1 * (E1)e2++; with (e1 * (E1)e2)++;, we'll get

Cast E1 -> E2
E1 * E1
E1 Post-inc
like image 27
Sergey Avatar answered Sep 21 '22 15:09

Sergey