2017-04-24 1 views
0

Der folgende Code zeigt, wie ein constexpr operator++() (Pre-Inkrement) verwendet werden kann (live demo). Jetzt frage ich mich, ob es sinnvoll ist, einen Post-Inkrement-Operator als constexpr zu deklarieren. Ich gehe davon aus, dass ein solcher Operator keine Nebenwirkungen hat und ähnlich wie im Beispiel verwendet wird. (Wenn dies zu abstrakt ist. Ich beabsichtige, meine bitset2 Klasse zu erweitern und will wissen, ob es ein Nutzen wäre, wenn die Post-Inkrementoperator constexpr ist)Gibt es eine Anwendung für einen consExpr-Operator? ++ (int) (Post-Inkrement)

struct S { 
    constexpr S(int i) : m_i(i) {} 
    constexpr S & operator++() { 
     ++m_i; 
     return *this; 
    } 
    int m_i; 
}; 

int main() { 
    constexpr auto s1= ++S{3}; 
    std::cout << s1.m_i << '\n'; // output: 4 
} 

Antwort

2

Ja, es hat eine Anwendung: Das Definieren eines Post-Inkrement-Operators könnte zum Schreiben von constexpr-Funktionen nützlich sein. Beachten Sie Folgendes:

tempalte<std::size_t N> 
constexpr std::array<baz,N> foo(){ 
    std::array<baz,N> bar; 
    baz i; 
    for(auto&& item: bar) { 
     item = i++; 
    } 
    return bar; 
} 

Das Array bar in dem obigen Beispiel wird bei der Kompilierung über die constexpr gefüllt werden. Nehmen wir an, der Typ baz ist eine Art von Zähler, die Reihenfolge der Operationen (vor/nach) für das Inkrement könnte wichtig sein.

Die Sache zu beachten ist, dass ein constexpr ein Ausdruck nicht nur ein Wert ist. Es ist erlaubt, komplexe (im Rahmen der Regeln für consExpr natürlich) Berechnungen, die in einen Constexpr gehen. Theoretisch könnten Sie viele Programme komplett als constexpr schreiben (obwohl ich nicht sage, dass es eine gute Idee wäre).

+0

'return bar;'. Warum referenzieren Sie doppelt "item" in der Schleife? Du bewegst nichts ... – JHBonarius

+1

@ J.H.Bonarius reparierte die fehlende Rückkehranweisung. Und nein, ich bewege nichts, aber die bereichsbasierte for-Schleife erzeugt eine temporäre von der Dereferenzierung des Iterators, den ich über eine r-Wert-Referenz erfasse, anstatt den Wert zu kopieren. Es könnte sehr gut auf verschiedene andere Arten geschrieben werden. –

+0

Ja, dein Beispiel überzeugt mich. Ich habe es auf mein erstes Beispiel angewendet ([link] (https://wandbox.org/permlink/6k8Vuq1rVl0yM1M9)). Das Entfernen von 'constexpr' für den Post-Inkrement-Operator wird nicht kompiliert. –

0

Ich weiß nicht, ob es sinnvoll ist, aber Sie können Ihre Prä-Inkrement Beispiel in einer Post-Inkrement ein

A übersetzbar Beispiel

#include <iostream> 

struct S 
{ 
    constexpr S (int i) : m_i{ i } 
    { } 

    constexpr S & operator++() 
    { 
     ++m_i; 
     return *this; 
    } 

    constexpr S operator++ (int) 
    { 
     S ret { this->m_i ++ }; 
     return ret; 
    } 

    int m_i; 
}; 

int main() 
{ 
    constexpr S s1 { ++S{3} }; 
    constexpr S s2 { S{4}++ }; 

    static_assert(s1.m_i == s2.m_i, "!"); 
} 

Und mit beiden constexpr Operatoren duplizieren, können Sie constexpr Funktionen wie

schreiben
constexpr S foo (int a, int b) 
{ 
    S s1 { a }; 
    S s2 { b }; 

    bool test { (s1++).m_i == (++s2).m_i }; 

    return test ? s1 : s2; 
} 
+1

Das Wiederholen der Logik ist keine gute Idee - Sie sollten einfach 'operator ++()' aufrufen. – Barry

+0

@Barry - Ich weiß, aber auf diese Weise können Sie einfach 'S' mit einem inkrementierten Wert konstruieren (' conetexpr auto s1 = S {4}; '). Es ist nützlich, einen Constexpr Pre-Increment-Operator? Wie auch immer, ich habe ein weiteres funktionsbasiertes (aber nützliches?) Beispiel hinzugefügt. – max66

Verwandte Themen