Frage

C ++ 11 einleitet

War es hilfreich?

Lösung

Hier ist ein Fall, in dem es ein Vorteil ist, benutzerdefinierte Literale anstelle eines Konstruktoraufruf zu verwenden:

#include <bitset>
#include <iostream>

template<char... Bits>
  struct checkbits
  {
    static const bool valid = false;
  };

template<char High, char... Bits>
  struct checkbits<High, Bits...>
  {
    static const bool valid = (High == '0' || High == '1')
                   && checkbits<Bits...>::valid;
  };

template<char High>
  struct checkbits<High>
  {
    static const bool valid = (High == '0' || High == '1');
  };

template<char... Bits>
  inline constexpr std::bitset<sizeof...(Bits)>
  operator"" _bits() noexcept
  {
    static_assert(checkbits<Bits...>::valid, "invalid digit in binary string");
    return std::bitset<sizeof...(Bits)>((char []){Bits..., '\0'});
  }

int
main()
{
  auto bits = 0101010101010101010101010101010101010101010101010101010101010101_bits;
  std::cout << bits << std::endl;
  std::cout << "size = " << bits.size() << std::endl;
  std::cout << "count = " << bits.count() << std::endl;
  std::cout << "value = " << bits.to_ullong() << std::endl;

  //  This triggers the static_assert at compile time.
  auto badbits = 2101010101010101010101010101010101010101010101010101010101010101_bits;

  //  This throws at run time.
  std::bitset<64> badbits2("2101010101010101010101010101010101010101010101010101010101010101_bits");
}

Der Vorteil ist, dass eine Laufzeitausnahme zu einem Fehler bei der Kompilierung umgewandelt wird. Sie können nicht die statische assert zum bitset Ctor fügen Sie eine Zeichenfolge (zumindest nicht ohne String-Vorlage Argument) nehmen.

Andere Tipps

Auf den ersten Blick scheint es einfach syntaktischer Zucker zu sein.

Aber wenn tiefer schauen, sehen wir es mehr als syntaktischer Zucker, wie es erweitert die C ++ Optionen des Benutzers benutzerdefinierte Typen zu erstellen, die genau verhalten sich wie verschiedene eingebauten Typen. Dabei diese wenig "Bonus" ist ein sehr interessantes C ++ 11 zusätzlich zu C ++.

Haben wir es wirklich brauchen in C ++?

Ich sehe einige Anwendungen in dem Code, den ich in den letzten Jahren geschrieben hätte, aber nur, weil ich es nicht in C ++ verwendet habe, bedeuten nicht, es nicht interessant ist für eine anderen C ++ Entwickler .

Wir hatten in C ++ verwendet (und in C, ich denke), Compiler definierte Literale, ganze Zahlen als kurze oder lange ganze Zahlen, reelle Zahlen als float oder double (oder sogar long double) und Zeichenketten als normal geben oder breite Zeichen.

In C ++, hatten wir die Möglichkeit, unsere eigenen Typen zu erstellen (d Klassen), mit möglicherweise kein Overhead (inlining, etc.). Wir hatten die Möglichkeit Betreiber ihre Typen hinzuzufügen, so dass sie wie ähnlich zu verhalten zu haben eingebauten Typen, die C ++ Entwicklern ermöglicht, Matrizen und komplexe Zahlen als natürlich zu verwenden, wie sie haben würden, wenn diese sich auf die Sprache hinzugefügt wurden. Wir können sogar Cast-Operatoren hinzufügen (das ist in der Regel eine schlechte Idee, aber manchmal ist es genau die richtige Lösung).

Wir verpassten noch eine Sache Benutzer-Typen zu haben, verhalten sich wie integrierte Typen:. Benutzerdefinierte Literalen

Also, ich denke, es ist eine natürliche Entwicklung für die Sprache, sondern so vollständig wie möglich zu sein: „ Wenn Sie einen Typ erstellen möchten, und Sie wollen es so viel möglich, als ein verhalten eingebauten Typen hier sind die Werkzeuge, ... "

Ich würde vermuten, es zu .NET Entscheidung sehr ähnlich ist jede primitive eine Struktur, einschließlich booleans, ganze Zahlen, usw. zu machen, und haben alle Strukturen von Objekt abzuleiten. Diese Entscheidung allein bringt .NET weit über Java Reichweite, wenn sie mit Primitiven arbeiten, egal wie viel Boxen / Unboxing Hacks Java mit der Spezifikation hinzugefügt werden.

Haben Sie es wirklich brauchen in C ++?

Diese Frage ist für Sie zu beantworten. Nicht Bjarne Stroustrup. Nicht Herb Sutter. Nicht alles Mitglied von C ++ Standard Committee. Aus diesem Grunde Sie die Wahl in C ++ haben , und sie werden nicht eine nützliche Notation eingebaute Typen allein beschränken.

Wenn Sie es brauchen, dann ist es eine willkommene Ergänzung. Wenn Sie nicht, na ja ... Sie es nicht verwenden. Es kostet Sie nichts.

Willkommen in C ++, die Sprache, wo Funktionen sind optional.

Bloated ??? Zeigen Sie mir Ihre Komplexe !!!

Es gibt einen Unterschied zwischen aufgebläht und komplexem (Wortspiel beabsichtigt).

Wie von Niels unter Welche neue Funktionen haben benutzerdefinierte Literale C ++ hinzufügen , eine komplexe Zahl zu schreiben in der Lage ist, eine der beiden Funktionen hinzugefügt? ‚kürzlich‘ auf C und C ++:

// C89:
MyComplex z1 = { 1, 2 } ;

// C99: You'll note I is a macro, which can lead
// to very interesting situations...
double complex z1 = 1 + 2*I;

// C++:
std::complex<double> z1(1, 2) ;

// C++11: You'll note that "i" won't ever bother
// you elsewhere
std::complex<double> z1 = 1 + 2_i ;

Nun, beide C99 "double-Komplex" Typ und C ++ "std :: complex" Typ sind in der Lage multipliziert werden, addiert, subtrahiert, usw., Überladen von Operatoren verwendet wird.

Aber in C99, sie haben soeben einen anderen Typ als integrierter Typ und Einbau-Betreiber Überlastung Unterstützung. Und sie fügte eine andere hinzuen Einbau-wörtliche Funktion.

In C ++, sie vorhandene Funktionen der Sprache nur verwendet, sah, dass die wörtliche Merkmal eine natürliche Entwicklung der Sprache war, und so fügte es.

C, wenn Sie die gleiche Schreibweise Erweiterung für eine andere Art benötigen, sind Sie kein Glück, bis Ihr Lobbying Ihre Quantenwellenfunktionen (oder 3D-Punkte hinzuzufügen, oder was auch immer Grundtyp Sie in Ihrem Arbeitsfeld mit ) mit dem C-Standard als integriertem Typ erfolgreich ist.

In C ++ 11, Sie können es sich einfach machen:

Point p = 25_x + 13_y + 3_z ; // 3D point

Ist es aufgebläht? Nein , ist die Notwendigkeit da, wie durch, wie beide C und C ++ Komplexe brauchen eine Möglichkeit, ihre wörtliche comp darstellenlex Werte.

Ist es falsch ausgelegt? Nein , es ist entworfen, wie jeder andere C ++ Funktion im Sinne der Erweiterungs.

Ist es für nur Notation Zwecke? Nein , wie es auch die Typsicherheit, um Ihren Code hinzufügen kann.

Zum Beispiel, lassen Sie uns einen CSS orientierten Code vorstellen:

css::Font::Size p0 = 12_pt ;       // Ok
css::Font::Size p1 = 50_percent ;  // Ok
css::Font::Size p2 = 15_px ;       // Ok
css::Font::Size p3 = 10_em ;       // Ok
css::Font::Size p4 = 15 ;         // ERROR : Won't compile !

Es ist dann sehr einfach, eine starke Typisierung der Zuordnung von Werten zu erzwingen.

Sie ist gefährlich?

Gute Frage. Können diese Funktionen werden Namensraum? Wenn ja, dann Jackpot!

Wie auch immer, wie alles, können Sie sich selbst töten, wenn ein Werkzeug falsch verwendet wird. C ist mächtig, und man kann den Kopf schießen, wenn Sie die C Waffe missbrauchen. C ++ hat die C-Waffe, sondern auch das Skalpell, die Taser, und was auch immer anderes Werkzeug, das Sie im Toolkit finden. Sie können das Skalpell mißbrauchen und sich zu Tode bluten. Oder Sie können sehr elegant und robusten Code bauen.

So, wie jeder C ++ Funktion, brauchen Sie wirklich? Es ist die Frage, die Sie vor der Verwendung in C ++ beantworten muss. Wenn Sie nicht tun, wird es kostet Sie nichts. Aber wenn Sie wirklich tun müssen es zumindest die Sprache werden Sie nicht im Stich lassen.

Das Datum Beispiel?

Ihr Fehler, so scheint es mir, ist, dass Sie Misch Operatoren:

1974/01/06AD
    ^  ^  ^

Das kann nicht vermieden werden, weil / ein Operator ist, der Compiler es interpretieren muss. Und AFAIK, es ist eine gute Sache.

Um eine Lösung für Ihr Problem zu finden, würde ich die wörtliche auf andere Weise schreiben. Zum Beispiel:

"1974-01-06"_AD ;   // ISO-like notation
"06/01/1974"_AD ;   // french-date-like notation
"jan 06 1974"_AD ;  // US-date-like notation
19740106_AD ;       // integer-date-like notation

Persönlich würde ich die ganze Zahl und die ISO wählt Daten, aber es hängt von Ihren Bedürfnissen. Welches ist der springende Punkt bei der Vermietung der Benutzer seine eigenen Literalnamen definieren.

Es ist sehr schön für mathematischen Code. Aus meinem Verstand heraus kann ich den Einsatz für folgende Operatoren finden Sie unter:

deg für Grad. Das macht absoluten Winkel Schreibt viel intuitiver.

double operator ""_deg(long double d)
{ 
    // returns radians
    return d*M_PI/180; 
}

Es kann auch für verschiedene feste Punktdarstellungen verwendet wird (die nach wie vor im Bereich der DSP und Grafiken in Gebrauch sind).

int operator ""_fix(long double d)
{ 
    // returns d as a 1.15.16 fixed point number
    return (int)(d*65536.0f); 
}

Diese sieht aus wie schöne Beispiele, wie es zu benutzen. Sie helfen Konstanten in Code besser lesbar zu machen. Es ist ein weiteres Werkzeug, um Code nicht lesbar sowie zu machen, aber wir haben schon so viele Werkzeuge missbrauchen, dass man mehr nicht viel schaden.

UDLs ist Namensraum (und kann mit Erklärungen / Richtlinien eingeführt werden, aber man kann nicht explizit ein wörtliche wie 3.14std::i Namensraum), was es bedeutet, (hoffentlich) nicht eine Tonne von Auseinandersetzungen sein.

Die Tatsache, dass sie tatsächlich werden als Templat (und constexpr'd) bedeutet, dass Sie ein paar ziemlich starke Sache mit UDLs tun können. Bigint Autoren werden wirklich glücklich sein, da sie schließlich beliebig große Konstanten haben können, bei der Kompilierung berechnet (über constexpr oder Vorlagen).

Ich bin nur traurig, dass wir ein paar nützlichen Literale in der Norm nicht sehen (von den Blicken von ihm), wie s für std::string und i für die imaginäre Einheit.

Die Menge der Codierung Zeit, die durch UDLs gespeichert wird, ist eigentlich nicht so hoch, aber die Lesbarkeit erhöht wird erheblich mehr und mehr Berechnungen können verschoben werden, um eine schnellere Ausführung zu kompilieren Zeit.

Lassen Sie mich ein wenig Kontext hinzufügen. Für unsere Arbeit, benutzerdefinierte Literalen ist dringend erforderlich. Wir arbeiten an MDE (Model-Driven Engineering). Wir wollen Modelle und Metamodelle in C ++ definieren. Wir führten tatsächlich eine Abbildung von Ecore zu C ++ ( EMF4CPP ).

Das Problem kommt, wenn die Lage zu Modellelementen wie Klassen in C ++ zu definieren. Wir nehmen den Ansatz, den Metamodell der Transformation (Ecore) zu Vorlagen mit Argumenten. Argumente der Vorlage sind die strukturellen Merkmale von Typen und Klassen. Zum Beispiel wäre eine Klasse mit zwei int Attributen so etwas wie:

typedef ::ecore::Class< Attribute<int>, Attribute<int> > MyClass;

Hoever, es stellt sich heraus, dass jedes Element in einem Modell oder Metamodell, in der Regel einen Namen hat. Wir möchten uns schreiben:

typedef ::ecore::Class< "MyClass", Attribute< "x", int>, Attribute<"y", int> > MyClass;

ABER, C ++, noch C ++ 0x dies nicht erlauben, als Strings als Argumente an Vorlagen sind verboten. Sie können den Namen char von char schreiben, aber das ist admitedly ein Chaos. Mit der richtigen benutzerdefinierten Literale, könnten wir etwas Ähnliches schreiben. Sagen wir „_n“ verwenden Modellelementnamen zu identifizieren (I, nicht die genaue Syntax nur eine Idee zu machen):

typedef ::ecore::Class< MyClass_n, Attribute< x_n, int>, Attribute<y_n, int> > MyClass;

Schließlich hilft uns, diese Definitionen als Vorlagen mit Algorithmen viel zu entwerfen, um die Modellelemente zum Verfahren, Modelltransformationen usw., die wirklich effizient sind, weil Typinformationen, die Identifizierung, Transformationen, usw. durch den Compiler bei der Kompilierung festgelegt werden Zeit.

Bjarne Stroustrup spricht über UDL die in diesem C + +11 sprechen , im ersten Abschnitt auf Typen-reiche Schnittstellen, etwa 20 Minuten-Marke.

Sein Hauptargument für UDLs nimmt die Form eines Syllogismus:

  1. "Trivial" Typen, das heißt, built-in primitiven Typen können nur triviale Art Fehler fangen. Schnittstellen mit reichen Typen erlaubt der Art System, um mehr Arten von Fehlern zu fangen.

  2. Die Arten von Typ-Fehler, die reich typisierte Code fangen Auswirkungen auf die echten Code haben kann. (Er gibt das Beispiel der Mars Climate Orbiter, die infamously auf einen Dimension Fehler in einer wichtigen Konstante scheitern).

  3. In echtem Code, Einheiten werden selten verwendet. Die Leute benutzen sie nicht, weil anfallenden Laufzeit berechnen oder Speicher-Overhead reiche Typen zu erstellen ist zu teuer, und Code vorbestehenden C ++ Templat-Einheit verwenden, ist so notationally hässlich, dass niemand es verwendet. (Empirisch nutzt niemand, auch wenn die Bibliotheken für ein Jahrzehnt gewesen sind).

  4. Um daher Ingenieure Einheiten in echtem Code zu verwenden, um zu bekommen, mussten wir ein Gerät, das (1) Overhead keine Laufzeit verursacht und (2) ist notationally akzeptabel.

Unterstützung Compiler-Dimension Prüfung ist die einzige Rechtfertigung erforderlich.

auto force = 2_N; 
auto dx = 2_m; 
auto energy = force * dx; 

assert(energy == 4_J); 

Siehe zum Beispiel PhysUnits-CT-Cpp11 , einen kleinen C ++ 11, C ++ 14-Header -nur Bibliothek zur Kompilierung-dimensionalen Analyse und Einheit / Menge Manipulation und Konvertierung. Simpler als Boost.Units , hat Unterstützung unit Symbol solche Literale als m, g, s, metric Präfixe wie m, k, m, hängt nur von Standard-C ++ Bibliothek, SI-only, ganzzahlige Potenzen von Dimensionen.

Hmm ... Ich habe noch über diese Funktion nicht gedacht. Ihre Probe wurde gut durchdacht und ist sicherlich interessant. C ++ ist sehr leistungsfähig, wie es jetzt ist, aber leider ist die Syntax in Teile des Codes verwendet man manchmal lesen ist zu komplex. Ablesbarkeit ist, wenn nicht alle, so doch zumindest viel. Und ein solches Merkmal würde für mehr Lesbarkeit ausgerichtet sein. Wenn ich Ihr letztes Beispiel nehmen

assert(1_kg == 2.2_lb); // give or take 0.00462262 pounds

... Ich frage mich, wie Sie das heute ausdrücken würde. Sie würden eine KG und eine LB-Klasse haben, und Sie würden implizite Objekte vergleichen:

assert(KG(1.0f) == LB(2.2f));

Und das würde auch tun. Bei den Typen, die längeren Namen oder Typen, die Sie haben keine Hoffnung, die so einen schönen Konstruktor für sans einen Adapter zu schreiben, könnte es eine schöne Ergänzung für seine implizite Objekterstellung und Initialisierung on-the-fly. Auf der anderen Seite können Sie bereits erstellen und Objekte mit Methoden initialisieren, zu.

Aber ich stimme mit Nils auf Mathematik. C und C ++ trigonometrischen Funktionen zum Beispiel erfordern Eingabe in Radiant. Ich denke aber, in Grad, so dass eine sehr kurze implizite Konvertierung wie Nils geschrieben ist sehr schön.

Schließlich, es wird jedoch syntaktischer Zucker sein, aber es wird eine geringe Wirkung auf die Lesbarkeit haben. Und es wird wahrscheinlich einfacher sein, auch einige Ausdrücke zu schreiben (sin (180.0deg) leichter ist als die Sünde zu schreiben (deg (180,0)). Und dann wird es Leute geben, die das Konzept missbrauchen. Aber dann, sprechen missbräuchlichen Menschen sollten verwenden sehr restriktive Sprachen eher als etwas so ausdrucksstark wie C ++.

Ach, mein Post sagt im Grunde nichts anderes als: es geht in Ordnung zu sein, werden die Auswirkungen nicht zu groß sein. Lassen Sie sich keine Sorgen machen. : -)

Ich habe noch nie benötigt oder diese Funktion wollte (aber dies könnte der Blub Effekt) . Mein Knie Ruck Reaktion ist, dass es lahm, und wahrscheinlich die gleichen Menschen ansprechen, die denken, dass es cool ist, +, um eine Überlastung Operator für jede Operation, die die Ferne als Zugabe verstanden werden könnte.

C ++ ist in der Regel sehr streng über die Syntax verwendet - abgesehen von dem Präprozessor gibt es nicht viel können Sie eine benutzerdefinierte Syntax / Grammatik definieren verwenden. Z.B. wir können bestehende operatos überlasten, aber wir können neue nicht definieren - IMO dies sehr viel mit dem Geist des C in der Melodie ++.

ich einige Möglichkeiten für individuellere Quellcode nichts dagegen tun - aber der gewählte Punkt scheint mir sehr isoliert, was mich verwirrt die meisten.

Auch bestimmungsgemäßen Gebrauch kann es viel schwieriger Quellcode zu lesen: ein einzelner Buchstabe große reichende Nebenwirkungen haben kann, dass in keine Weise aus dem Kontext identifiziert werden. Mit Symmetrie u, l und f, werden die meisten Entwickler einzelne Buchstaben wählen.

Dies kann auch wiederum in ein Problem Scoping, werden einzelne Buchstaben im globalen Namespace wahrscheinlich schlechte Praxis in Betracht gezogen werden, und die Werkzeuge, die Bibliotheken einfacher werden soll Mischen (Namespaces und beschreibenden Bezeichner) wird wahrscheinlich seinen Zweck besiegen.

Ich sehe einen gewissen Wert in Kombination mit "auto", auch in Kombination mit einer Einheit Bibliothek wie Boost-Einheiten , aber nicht genug, um diese adition zu verdienen.

Ich frage mich aber, was für kluge Ideen, die wir kommen mit.

Ich habe Benutzer Literale für Binärketten wie folgt aus:

 "asd\0\0\0\1"_b

std::string(str, n) Konstruktor, so dass \0 nicht die Zeichenfolge halbiert würde. (Das Projekt hat eine Menge Arbeit mit verschiedenen Dateiformaten.)

Dies war auch hilfreich, wenn ich std::string zugunsten eines Wrappers für std::vector ditched.

Line Rauschen in diesem Ding ist riesig. Auch es ist schrecklich zu lesen.

Lassen Sie uns wissen, haben sie Grund, dass neue Syntax zusätzlich mit jeder Art von Beispielen? Zum Beispiel haben sie einige Programme, die bereits C ++ 0x verwenden?

Für mich ist dieser Teil:

auto val = 3.14_i

Ist dieses Teil nicht rechtfertigen:

std::complex<double> operator ""_i(long double d) // cooked form
{ 
    return std::complex(0, d);
}

Nicht einmal, wenn Sie die i-Syntax in 1000 anderen Linien als auch verwenden würden. Wenn Sie schreiben, schreiben Sie wahrscheinlich 10000 Zeilen von etwas anderem zusammen das auch. Vor allem, wenn Sie werden wahrscheinlich immer noch schreiben meist überall so aus:

std::complex<double> val = 3.14i

'auto' -Keyword obwohl gerechtfertigt sein kann, vielleicht nur. Aber können einfach und C ++, weil es ist besser als C ++ 0x in diesem Aspekt.

std::complex<double> val = std::complex(0, 3.14);

Es ist wie .. so einfach. Auch dachte die ganze std und spitze Klammern sind nur lahm, wenn Sie es überall verwenden. Ich vermute, nicht starten, was Syntax es in C ++ 0x ist zum Drehen std :: Komplex unter komplex.

complex = std::complex<double>;

Das ist vielleicht etwas einfach, aber ich glaube nicht, es ist so einfach in C ++ 0x.

typedef std::complex<double> complex;

complex val = std::complex(0, 3.14);

Vielleicht? > :)

Wie auch immer, der Punkt ist: Schreiben 3.14i statt std :: Komplex (0, 3,14); nicht, dass Sie viel Zeit in insgesamt sparen, außer in einigen Supersonderfälle.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top