2016-07-11 18 views
5

Na stronie internetowej http://en.cppreference.com/w/cpp/language/fold daje przykład, jak używać krotny koncepcję, i mówi:C++ 17: Co oznacza "operator o pierwszeństwie pod rzutem" w koncepcji "krotnie"?

Jako non-native speakera angielskiego, nie rzucić się zdanie:

has an operator with precedence below cast at the top level 

Co to właściwie oznacza, a na przykład, co to oznacza? Czy możesz pomóc w wyjaśnieniu tego?

Wielkie dzięki.

+3

Oznacza to nic poniżej linii 3 w tabeli pierwszeństwa [] (http://en.cppreference.com/w/cpp/language/operator_precedence). –

Odpowiedz

7

Operator odlewu ((Typename)expr) ma bardzo wysokie pierwszeństwo w C++'s operator precedence rules. Bardzo niewielu operatorów ma wyższy priorytet. Operatory o wyższym lub niższym priorytecie są operacjami specjalnymi, zwykle stosującymi się do pojedynczego wyrażenia.

W wyrażeniu args + ... + 1 * 2, dotyczy wszystkiego zarówno po lewej, jak i po prawej stronie. Ale co naprawdę oznacza "na prawo"? Czy to oznacza tylko część + 1, czy też oznacza ona + 1 * 2?

W przypadku operatorów o wysokim priorytecie, jasne jest, jakie są intencje. Na przykład: args + ... + func(), oczywiste jest, że operator wywołania funkcji () stosuje się do func, a nie do args + ... + func. Jest tak mało prawdopodobne, że chcesz tego drugiego, jeśli musisz go użyć jawnie, jeśli to zrobiłeś ((args + ... + func)()).

Jednak dla poziomów pierwszeństwa poniżej 3 na wykresie rzeczy stają się znacznie bardziej mętne, aby ludzie mogli je zrozumieć. Zamiast więc używać normalnych reguł pierwszeństwa, C++ zmusza użytkownika do wyraźnego wyrażania się na jego temat. Możesz mieć args + ... + (1 * 2) lub (args + ... + 1) * 2. Ale musisz jasno wiedzieć, który z nich chcesz.

+0

Twoje wyjaśnienie jest dla mnie jasne. –

+1

Ponieważ wyrażenia fold są '(exp1 op ... op exp2)' z parens, wątpię, że istnieje rzeczywiste parsowanie niejednoznaczności. Prawdopodobnie jest tak, aby było jasne dla ludzi, nie tylko dla kompilatorów. –

1

Oznacza to, że jeśli wyrażenie z kilkoma operatorami jest niejednoznaczne, operatory, które są "nadlewane", zostaną wywołane przed operatorem obsady, a operatorzy, którzy są "pod rzutem", zostaną wywołani po operatorze rzutowania. Jak w 2 + 2 * 2 mnożenia powinny być wykonane przed dodaniem, wynikające 6, ale nie 8.

Rozważmy następujące dwie klasy, które są rzutować siebie:

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

takim razie zadeklarować

E1 e1; 
E2 e2; 

i do

(E1)e2++; 

Zarówno E1, jak i E2 mają operat lub ++, więc co należy zrobić najpierw w tym wyrażeniu: rzut lub przyrost? Precedence table odpowiedzi, że przyrost powinien być wykonane w pierwszej kolejności, a więc program wypisuje

E2 Post-inc 
Cast E1 -> E2 

Następnie spróbujmy bardziej skomplikowany przykład:

e1 * (E1)e2++; 

Tu mamy 3 działania (w kolejności ich pojawienia się w kodzie) : mnożenie, rzucanie i przyrost. Co się stanie, jeśli wykonanie będzie?Tabela pierwszeństwa mówi, że inkrementacja jest pierwszym, rzut jest drugim (jest poniżej przyrostu), a mnożenie jest ostatnim, ponieważ znajduje się poniżej nich. Więc wyjście będzie:

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

Pamiętaj, że możesz łatwo zmienić kolejność operacji za pomocą nawiasów. Na przykład, jeśli wymienimy e1 * (E1)e2++; z (e1 * (E1)e2)++;, będziemy się

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

Dobra odpowiedź, dzięki! –