Pergunta

É a && b && c definido pela linguagem para significar (a && b) && c ou a && (b && c)?

Uau, Jerry foi rápido.Para reforçar a questão:isso realmente importa?Haveria uma diferença observável entre a && b && c sendo interpretado como (a && b) && c ou a && (b && c)?

Foi útil?

Solução

§5.14/1:"O operador && agrupa da esquerda para a direita....] ao contrário de & && garante avaliação da esquerda para a direita:o segundo operando não é avaliado se o primeiro operando for falso."

Quanto a quando ou como isso importa:Não tenho certeza se isso realmente acontece com os tipos integrados.É possível, no entanto, sobrecarregá-lo de uma forma que faça com que tenha importância.Por exemplo:

#include <iostream>

class A;

class M {
    int x;
public:
    M(int x) : x(x) {}
    M &operator&&(M const &r); 
    M &operator&&(A const &r); 
    friend class A;
};

class A {
    int x;
    public:
    A(int x) : x(x) {}
    A &operator&&(M const &r); 
    A &operator&&(A const &r);
    operator int() { return x;}
    friend class M;
};

M & M::operator&&(M const &r) {
    x *= r.x;
    return *this;
}

M & M::operator&&(A const &r) {
    x *= r.x;
    return *this;
}

A &A::operator&&(M const &r) {
    x += r.x;
    return *this;
}

A &A::operator&&(A const &r) {
    x += r.x;
    return *this;
}

int main() {
    A a(2), b(3);
    M c(4);

    std::cout << ((a && b) && c) << "\n";
    std::cout << (a && (b && c)) << "\n";
}

Resultado:

9
16

Embargo:isso só mostra como é pode ser feito para importar.Eu sou não recomendando particularmente que qualquer pessoa o faça, apenas mostrando que, se você quiser muito, poderá criar uma situação em que isso faça a diferença.

Outras dicas

O && e || curto-circuito dos operadores:se o operando à esquerda determinar o resultado da expressão geral, o operando à direita nem mesmo será avaliado.

Portanto, um matemático os descreveria como associativos à esquerda, por ex.
a && b && c(a && b) && c, porque para um matemático isso significa a e b são considerados em primeiro lugar.Para fins pedagógicos, porém, pode ser útil escrever a && (b && c) em vez disso, para enfatizar que nenhum b nem c será avaliado se a é falso.

Os parênteses em C só alteram a ordem de avaliação quando substituem precedência.Ambos a && (b && c)
e (a && b) && c será avaliado como a primeiro, então b, então c.Da mesma forma, a ordem de avaliação de ambos
a + (b + c) e (a + b) + c não é especificado.Contraste a + (b * c) contra (a + b) * c, onde o compilador ainda está livre para avaliar a, b, e c em qualquer ordem, mas os parênteses determinam se a multiplicação ou a adição acontece primeiro.Compare também o FORTRAN, onde em pelo menos alguns casos as expressões entre parênteses devem ser avaliadas primeiro.

Na verdade é muito importante que a expressão seja calculada da esquerda para a direita.Isso é usado para causar curto-circuito em algumas expressões.Aqui está um caso em que isso importa:

vector<vector<int> > a;
if (!a.empty()  && !a[0].empty() && a[0].back() == 3) 

Aposto que você escreve declarações semelhantes algumas vezes por dia.E se a associatividade não fosse definida, você estaria em apuros.

Se a && b é falso, então o && c parte nunca é testada.Então sim, isso importa (pelo menos porque você precisa ter suas operações ordenadas da esquerda para a direita). && é uma operação associativa por natureza.

Propriedade associativa

Dentro de uma expressão contendo duas ou mais ocorrências em uma linha do mesmo operador associativo, a ordem em que as operações são realizadas não importa, desde que a sequência dos operandos não seja alterada.Ou seja, reorganizar os parênteses nessa expressão não alterará seu valor.

Portanto, não importa (logicamente) se você escrever como a && (b && c) ou (a && b) && c.Ambos são equivalentes.Mas você não pode alterar a ordem das operações (por exemplo a && c && b não é equivalente a a && b && c).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top