Hypercell ein ] Hypercell aus ] Zeige Navigation ] Verstecke Navigation ]
c++.de  
   
Forentreff 2012     
Bücher-Shop mit Amazon (Buchkategorien)C++ : Referenzen zu C++ : C++ Builder : Visual C++ : C# : Java : Spieleprogrammierung : Systemprogrammierung Linux : Software-Entwicklung : .NET : Compilertechnik : Algorithmen & Datenstrukturen : Objektorientierung : Entwurfsmuster : UML : eXtreme Programming : Scrum : Projektmanagement : Software-Testing : Datenbanken : Tom DeMarco : Dilbert : User Friendly
C/C++ Forum :: Die Artikel ::  C++09 (Teil 1) - Ein Überblick: Sprachfeatures     Zeige alle Beiträge auf einer Seite Auf Beitrag antworten
Autor Nachricht
queer_boy
Mitglied

Benutzerprofil
Anmeldungsdatum: 02.11.2006
Beiträge: 1035
Beitrag queer_boy Mitglied 20:05:55 05.02.2008   Titel:   C++09 (Teil 1) - Ein Überblick: Sprachfeatures            Zitieren

C++09 (Teil 1) - Ein Überblick: Sprachfeatures

Update: Alle hier vorgestellten Features sind im Working Draft enthalten und werden sehr wahrscheinlich Teil von C++0x

C++ ist seit der Veröffentlichung des internationalen Standards 1998 schon etwas in die Jahre gekommen. Zwar gab es 2003 eine Überarbeitung, die einige Makel behoben hat, jedoch an den Grundstrukturen der Sprache nicht wirklich etwas verändert hat.

Der nächste, ziemlich große Sprung, wird die Veröffentlichung eines neuen internationalen C++-Standards, vermutlich 2009, sein. C++09 ist eine Überarbeitung, die in vielen Bereichen der Sprache grundlegende Änderungen vornimmt. Auch die Standardbibliothek wird um einiges vielfältiger. Oft liest man auch die Bezeichnung C++0x. Ich habe hier bewusst C++09 genommen, um den Standard auch vom Namen her "greifbarer" zu machen.

Da wir mittlerweile schon 2008 schreiben, liegt die Veröffentlichung des neuen Standards in nicht allzu weiter Ferne und von vielen Features lässt sich schon fix sagen, dass sie dabei sein werden. Besser noch: So manch aktueller Compiler (GCC 4.3 und 4.4, Comeau ab 4.3.9) implementiert bereits einige Neuerungen.

Dieser Artikel ist Beginn einer Reihe, die sich mit den wichtigsten und sichtbarsten Neuerungen befasst. Hier soll zunächst ein grober Überblick über die neuen Sprachfeatures gegeben werden. Da C++09 sehr viel Neues enthält, ist klar, dass nicht auf alles im Detail eingegangen werden kann. Ich beschränke mich hier auf die "wichtigsten" und "sichtbarsten" Features, das sind jene Möglichkeiten, die am meisten ins Auge stechen und vermutlich den größten Einfluss auf den zukünftigen C++-Programmierstil haben werden. Da es jedoch immer noch eine persönliche Auswahl darstellt, ist klar, dass nicht jede Neuerung besprochen werden kann.

Da der neue C++-Standard noch nicht fertig ist, kann es natürlich sein, dass die eine oder andere Neurung im tatsächlichen Standard dann nicht oder nicht in der hier vorgestellten Form inkludiert sein wird. Der aktuelle Status der Features, die hier vorstellt werden, wird deshalb mitangegeben.

Inhalt

  • 1 Neue Konzepte
    • 1.1 Variadic Templates
    • 1.2 Rvalue-Referenzen: Move statt Copy
    • 1.3 concept und concept_map
    • 1.4 static_assert
    • 1.5 Über die neue Art, Funktionen zu deklarieren
    • 1.6 Lambda-Ausdrücke
    • 1.7 Neue Literale
  • 2 Bewährtes verbessert
    • 2.1 Templates neu
    • 2.2 Konstruktion von Objekten
    • 2.3 Konstante Ausdrücke
    • 2.4 for für Ranges
    • 2.5 Explizite Umwandlungsoperatoren
    • 2.6 Typsicheres enum
    • 2.7 default-Funktionen
    • 2.8 Plötzlich POD
    • 2.9 nullptr
  • 3 Ausblick
  • 4 Quellen und Verweise



1 Neue Konzepte

Die Features, die in diesem Teil aufgelistet sind, sind größere, zusammenhängende Neuerungen, die die Möglichkeit, Sachverhalte mit C++ auszudrücken, enorm verändern. Diese Änderungen stechen auch AnfängerInnen sofort ins Auge.

1.1 Variadic Templates

Oft ist es nötig, einem Template zu erlauben, eine beliebige Zahl von Argumenten entgegenzunehmen. Variadic Templates erlauben genau das.
Mehr noch: Mit ihnen kann man auch Funktionen definieren, die eine beliebige Anzahl von Argumenten annehmen können und dennoch typsicher sind. Damit erlauben Variadic Templates die einfachere, sauberere und wartbarere Implementierung beispielsweise von Tupel-Typen oder Funktionsobjekten und typsicheren Funktionen mit einer beliebigen Anzahl von Parametern wie std::make_shared (siehe C++09 (Teil 2) - Ein Überblick: Die Standardbibliothek).

In Zusammenhang mit Rvalue-Referenzen ermöglichen Variadic Templates so genanntes perfect forwarding, die perfekte Weitergabe von Argumenten durch verschiedene Funktionen. Ein Beispiel dafür findet sich im Kapitel über Rvalue-Referenzen (1.2).


Beispiel 1 - Variadic Klassentemplates
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//count_args zählt, mit wie vielen Template-Parametern es instanziiert wird
template <typename ...Args>
struct count_args;

template <>
struct count_args<>
{
   static int const value = 0;
};

template <typename T, typename ...Args>
struct count_args<T, Args...>
{
   static int const value = 1 + count_args<Args...>::value;
};

//Anwendung
assert (count_args<int, int, int>::value == 3);
assert (count_args<int, double, float, char>::value == 4);
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//count_args zählt, mit wie vielen Template-Parametern es instanziiert wird
template <typename ...Args>
struct count_args;

template <>
struct count_args<>
{
static int const value = 0;
};

template <typename T, typename ...Args>
struct count_args<T, Args...>
{
static int const value = 1 + count_args<Args...>::value;
};

//Anwendung
assert (count_args<int, int, int>::value == 3);
assert (count_args<int, double, float, char>::value == 4);
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//count_args zählt, mit wie vielen Template-Parametern es instanziiert wird
template <typename ...Args>
struct count_args;

template <>
struct count_args<>
{
   static int const value = 0;
};

template <typename T, typename ...Args>
struct count_args<T, Args...>
{
   static int const value = 1 + count_args<Args...>::value;
};

//Anwendung
assert (count_args<int, int, int>::value == 3);
assert (count_args<int, double, float, char>::value == 4);


Erläuterung
Das Template count_args ist, wie in der Template-Metaprogrammierung üblich, rekursiv über explizite Spezialisierung definiert.

Mit der Syntax template <typename ...Args> wird ein Template deklariert, das eine beliebige Anzahl (0-…) von Argumenten entgegennimmt. ...Args nennt man ein Parameter-Pack. Mithilfe des ...(Ellipsen oder Auslassungspunkt)-Operators wird dieses Pack "ausgepackt", aus count_args<Args...>::value wird hier also count_args<Arg1, Arg2, Arg3, ...>::value. (Anmerkung: Der Operator sizeof ... wird in C++09 die Funktion von count_args übernehmen.)


Beispiel 2 - Variadic Templates in Funktionen
C/C++ Code:
template <class T, typename ...Args>
T * make_new (Args&& ...args) //Das && deklariert eine Rvalue-Referenz. Siehe 1.2
{
   return new T(static_cast<Args&&>(args)...); //Entpackt wird so:
   //new T(static_cast<Arg1&&>(arg1), static_cast<Arg2&&>(arg2), ...)

}
C/C++ Code:
template <class T, typename ...Args>
T * make_new (Args&& ...args) //Das && deklariert eine Rvalue-Referenz. Siehe 1.2
{
return new T(static_cast<Args&&>(args)...); //Entpackt wird so:
//new T(static_cast<Arg1&&>(arg1), static_cast<Arg2&&>(arg2), ...)

}
C/C++ Code:
template <class T, typename ...Args>
T * make_new (Args&& ...args) //Das && deklariert eine Rvalue-Referenz. Siehe 1.2
{
   return new T(static_cast<Args&&>(args)...); //Entpackt wird so:
   //new T(static_cast<Arg1&&>(arg1), static_cast<Arg2&&>(arg2), ...)

}


Erläuterung
...Args erzeugt wie gehabt ein Parameter-Pack, doch diesmal genauer: ein Template-Parameter-Pack. Die Deklaration Args const& ...args erzeugt zwar auch ein Parameter-Pack, aber in diesem Fall ein Funktions-Parameter-Pack. Funktions-Parameter-Packs auszupacken, funktioniert genauso wie mit Template-Packs: args....

Generell lässt sich sagen, dass immer dann ein Parameter-Pack erzeugt wird, wenn der Ellipsis-Operator links von einem Namen steht und einen Parameter-Pack entpackt, wenn er rechts von ihm steht. Dabei spielt keine Rolle, wie kompliziert der Ausdruck ist, in dem ein Parameter-Pack erweitert (ausgepackt) wird.

C/C++ Code:
template <class T, class ...Args>
T* make_new (Args&& ...args)
{
   //expandiert automatisch richtig:
   return new T( *new Args(static_cast<Args&&>(args)) ...);
}
C/C++ Code:
template <class T, class ...Args>
T* make_new (Args&& ...args)
{
//expandiert automatisch richtig:
return new T( *new Args(static_cast<Args&&>(args)) ...);
}
C/C++ Code:
template <class T, class ...Args>
T* make_new (Args&& ...args)
{
   //expandiert automatisch richtig:
   return new T( *new Args(static_cast<Args&&>(args)) ...);
}



Status - Juni 2008
Variadic Templates sind bereits im derzeitigen Working-Draft des kommenden Standards enthalten.

Unterstützung
Die Implementierung für Compiler-Hersteller scheint nicht allzu schwer zu sein. GCC 4.3 unterstützt Variadic Templates, die Standardbibliothek libstdc++ 4.3 dieses Compilers stützt sich bereits darauf.

Proposals
N2080 - Hintergründe
N2087 - Eine kurze Einführung

1.2 Rvalue-Referenzen: Move statt Copy

Das Problem:

C/C++ Code:
1
2
3
4
5
6
7
8
9
1
2
3
4
5
6
7
8
9
string operator + (string const& a, string const& b)
{
   string tmp (a);
   tmp += b;
   return tmp;
}

string a ("this ");
string b = a + "a" + "b" + "cd";
C/C++ Code:
1
2
3
4
5
6
7
8
9
string operator + (string const& a, string const& b)
{
string tmp (a);
tmp += b;
return tmp;
}

string a ("this ");
string b = a + "a" + "b" + "cd";
C/C++ Code:
1
2
3
4
5
6
7
8
9
string operator + (string const& a, string const& b)
{
   string tmp (a);
   tmp += b;
   return tmp;
}

string a ("this ");
string b = a + "a" + "b" + "cd";

In dem Ausdruck b = a + … werden für jeden Aufruf von operator+ temporäre Objekte erzeugt, die anschließend in die lokale Variable tmp kopiert werden. Das ist nötig, da temporäre Objekte nur an konstante Referenzen gebunden werden können (und das aus gutem Grund). Damit wird für jeden Aufruf von operator+ (typischerweise) dynamischer Speicher allokiert. In obigen Ausdruck würde dies zumindest dreimal geschehen.

Mit Rvalue-Referenzen ist es möglich, statt ständig zu kopieren, den Inhalt der temporären Variablen zu verschieben - das ist sicher, denn temporäre Variablen existieren - wie ihr Name schon sagt - nur temporär, in unserem Fall gibt es sie nach Auswertung des Ausdrucks b = a + … nicht mehr.

Manche Objekte in C++ sind nicht kopierbar, können aber sehr wohl verschoben ("move") werden. Ein Beispiel dafür sind fstream-Objekte. Wenn diese Move-Semantik unterstützen, können sie auch jederzeit sicher in Standard-Containern aufbewahrt werden, da immer nur ein Objekt (bzw. dessen interne Repräsentation) und keine Kopie existiert.

In Kombination mit Variadic Templates ist perfect forwarding möglich, ebenso die Implementierung einer swap-Funktion, die ohne temporäre Kopie (und damit einer möglichen Allokation von dynamischem Speicher) arbeitet.


Beispiel - Optimierung von std::string
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
string&&
operator + (string&& a, string const& b)
{
   return a += b;
}

string&&
operator + (string const& a, string&& b)
{
   return b.insert(0, a);
}

string&&
operator+(string&& a, string&& b)
{
   return a += b;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
string&&
operator + (string&& a, string const& b)
{
return a += b;
}

string&&
operator + (string const& a, string&& b)
{
return b.insert(0, a);
}

string&&
operator+(string&& a, string&& b)
{
return a += b;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
string&&
operator + (string&& a, string const& b)
{
   return a += b;
}

string&&
operator + (string const& a, string&& b)
{
   return b.insert(0, a);
}

string&&
operator+(string&& a, string&& b)
{
   return a += b;
}


Erläuterung
Die Syntax T && t = T() bindet die Rvalue-Referenz t an ein temporäres Objekt T().
Die oben definierten Überladungen von operator+ können daher unterscheiden, ob sie temporäre Objekte (genauer: Rvalues) übergeben bekommen. Falls ein temporäres Objekt übergeben wurde, kann direkt mit diesem gearbeitet werden, was eine Allokation von neuem Speicher (meist) überflüssig macht. Sollte die NRVO (Named-Return-Value-Optimization) nicht funktionieren, wird auch das zurückgegebene Objekt nicht kopiert, sondern nur dessen Inhalt "verschoben", ein passender Move-Constructor, der Rvalue-Referenzen annimmt, vorausgesetzt.


Beispiel - Forwarding
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <utility>
#include
<memory>

struct A
{
   A (double&, float&, const int&);
};

template <class T, class ...Args>
shared_ptr<T>
factory_method (Args&&... args)
{
   return std::shared_ptr<T>(new T(std::forward(args)...));
}

//Anmerkung: Diese Funktion ist in <memory> als make_shared definiert.
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <utility>
#include
<memory>

struct A
{
A (double&, float&, const int&);
};

template <class T, class ...Args>
shared_ptr<T>
factory_method (Args&&... args)
{
return std::shared_ptr<T>(new T(std::forward(args)...));
}

//Anmerkung: Diese Funktion ist in <memory> als make_shared definiert.
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <utility>
#include
<memory>

struct A
{
   A (double&, float&, const int&);
};

template <class T, class ...Args>
shared_ptr<T>
factory_method (Args&&... args)
{
   return std::shared_ptr<T>(new T(std::forward(args)...));
}

//Anmerkung: Diese Funktion ist in <memory> als make_shared definiert.


Erläuterung
std::forward ist in <utility> definiert und gibt schlicht und einfach ihr Argument weiter. Wenn es eine Rvalue-Referenz übergeben bekommt, gibt es auch eine Rvalue-Referenz weiter. Ansonsten müsste man explizit casten.

Status - Juni 2008
Rvalue-Referenzen sind bereits im derzeitigen Working-Draft des kommenden Standards enthalten.

Unterstützung
Sowohl Rvalue-Referenzen als auch deren effektiver Einsatz in der Standardbibliothek werden von einigen Compilern unterstützt. Für obiges Beispiel string a = b + … braucht Metrowerks CodeWarrior Compiler nur einen einzige dynamische Speicherallokation. GCC 4.3 unterstützt Rvalue-Referenzen ebenso.

Proposals
N1690 - Anwendungsfälle für Rvalue-Referenzen
N2027 - Kurze Einführung

1.3 concept und concept_map

Concepts vereinfachen die Verwendung von Templates, indem sie sicherstellen, dass übergebene Template-Parameter sich an definierte Vorgaben halten. Seitenlange Fehlermeldungen, wie sie heute beim Einsatz von Templates oft vorkommen, können durch Concepts kürzer und damit aussagekräftiger gemacht werden. Im Grunde stellen Concepts ein Typsystem für Templates dar.


Beispiel 1 - Grundlagen
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
auto concept LessThanComparable <typename T>
{
   bool operator<(T, T);
};

template <LessThanComparable T>
T const& min (T const& a, T const& b)
{
   return a < b ? a : b;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
auto concept LessThanComparable <typename T>
{
bool operator<(T, T);
};

template <LessThanComparable T>
T const& min (T const& a, T const& b)
{
return a < b ? a : b;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
auto concept LessThanComparable <typename T>
{
   bool operator<(T, T);
};

template <LessThanComparable T>
T const& min (T const& a, T const& b)
{
   return a < b ? a : b;
}


Erläuterung
Das Concept LessThanComparable beschreibt alle Typen T, die einen operator< implementieren, der zwei Ts vergleichen kann und einen boolschen Wert zurückgibt.
Das Template min akzeptiert damit nur jene Typen, die dieses Concept unterstützen.
Sollten sie dies nicht tun, kann der Compiler eine aussagekräftige Fehlermeldung wie "Template-Parameter T unterstützt Concept LessThanComparable nicht" generieren.
Das auto bedeutet, dass jeder Typ, der die Bedingungen, die das Concept formuliert, unterstützt, automatisch auch das Concept unterstützt.


Beispiel 2 - Multityp-Bedingungen
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
1
2
3
4
5
6
7
8
9
10
11
auto concept Convertible <typename T, typename U>
{
   operator U (T const&);
};

template <typename U, typename T>
  requires Convertible<T, U>
U convert (T const& t)
{
   return t;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
auto concept Convertible <typename T, typename U>
{
operator U (T const&);
};

template <typename U, typename T>
requires Convertible<T, U>
U convert (T const& t)
{
return t;
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
auto concept Convertible <typename T, typename U>
{
   operator U (T const&);
};

template <typename U, typename T>
  requires Convertible<T, U>
U convert (T const& t)
{
   return t;
}


Erläuterung
Das Concept Convertible bezieht sich auf zwei Typen, die eine Konvertierungsbeziehung zueinander besitzen. Um dem Template convert zu sagen, dass es nur T-zu-U konvertierbare Typen akzeptieren soll, ist eine requires-Bedingung notwendig.


Beispiel 3 - Concept-Maps
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
concept InputIterator <typename Iter> //Ein Input-Iterator hat…
{
   typename value_type;               //einen Typ "value_type"
   typename reference;                //einen Typ "reference"
   typename pointer;                  //einen Typ "pointer"
   typename difference_type;          //einen Typ "difference_type"
                                      //und kann

   reference operator* (Iter const&); //dereferenziert werden
   Iter& operator ++ (Iter&);         //inkrementiert werden (prä)
   Iter& operator ++ (Iter&, int);    //inkrementiert werden (post)
};

concept_map InputIterator<char*>
{
   typedef char value_type;
   typedef char& reference;
   typedef char* pointer;
   typedef ptrdiff_t difference_type;
};
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
concept InputIterator <typename Iter> //Ein Input-Iterator hat…
{
typename value_type; //einen Typ "value_type"
typename reference; //einen Typ "reference"
typename pointer; //einen Typ "pointer"
typename difference_type; //einen Typ "difference_type"
//und kann

reference operator* (Iter const&); //dereferenziert werden
Iter& operator ++ (Iter&); //inkrementiert werden (prä)
Iter& operator ++ (Iter&, int); //inkrementiert werden (post)
};

concept_map InputIterator<char*>
{
typedef char value_type;
typedef char& reference;
typedef char* pointer;
typedef ptrdiff_t difference_type;
};
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
concept InputIterator <typename Iter> //Ein Input-Iterator hat…
{
   typename value_type;               //einen Typ "value_type"
   typename reference;                //einen Typ "reference"
   typename pointer;                  //einen Typ "pointer"
   typename difference_type;          //einen Typ "difference_type"
                                      //und kann

   reference operator* (Iter const&); //dereferenziert werden
   Iter& operator ++ (Iter&);         //inkrementiert werden (prä)
   Iter& operator ++ (Iter&, int);    //inkrementiert werden (post)
};

concept_map InputIterator<char*>
{
   typedef char value_type;
   typedef char& reference;
   typedef char* pointer;
   typedef ptrdiff_t difference_type;
};


Erläuterung
Concepts beschreiben eine gewisse Schnittstelle, mit der generische Algorithmen arbeiten können. So beschreibt das Concept InputIterator die von Input-Iteratoren geforderte Schnittstelle. Ein Zeiger (in diesem Fall auf char) besitzt jedoch nicht das verlangte Interface, vor allem nicht die Typen char*::value_type etc. Zu erwähnen ist außerdem, dass jeder Operator, der von einem Concept benötigt wird, innerhalb des Concepts als freistehende Definition deklariert werden muss.

Mit einer Concept-Map kann man nun für einen beliebigen Typ beschreiben, wie dessen Interface gegenüber einem gewissen Concept aussieht. Man sagt damit also, dass ein gewisser Typ ein Concept unterstützt - und wie er es unterstützt. Damit ist es möglich, Interfaces von selbstimplementierten Typen derart umzubiegen, dass sie bestimmte Concepts unterstützen.


Beispiel 4 - Schnittstellen verbiegen
Man stelle sich eine eigene Implementierung eines Strings vor, sowie ein Concept, das Strings beschreibt:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
1
2
3
4
5
6
7
8
9
10
11
concept String <typename S>
{
    //…
    S concatenate (S const&, S const&);
};

class MyString
{
     //…
     MyString mycat (MyString const& b);
};
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
concept String <typename S>
{
//…
S concatenate (S const&, S const&);
};

class MyString
{
//…
MyString mycat (MyString const& b);
};
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
concept String <typename S>
{
    //…
    S concatenate (S const&, S const&);
};

class MyString
{
     //…
     MyString mycat (MyString const& b);
};


Mit einer Concept-Map ist es nun möglich, zu sagen, dass MyString das Concept String unterstützt, ohne etwas an der eigentlichen Schnittstelle von MyString zu verändern.

C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
concept_map String<MyString>
{
   //…
   MyString concatenate (MyString const& a, MyString const& b)
   {
      S tmp(a);
      return tmp.mycat(b);
   }
};

concept_map String<std::string>
{
   //…
   std::string concatenate (std::string const& a, std::string const& b)
   {
      std::string tmp(a);
      return tmp += b;
   }
};
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
concept_map String<MyString>
{
//…
MyString concatenate (MyString const& a, MyString const& b)
{
S tmp(a);
return tmp.mycat(b);
}
};

concept_map String<std::string>
{
//…
std::string concatenate (std::string const& a, std::string const& b)
{
std::string tmp(a);
return tmp += b;
}
};
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
concept_map String<MyString>
{
   //…
   MyString concatenate (MyString const& a, MyString const& b)
   {
      S tmp(a);
      return tmp.mycat(b);
   }
};

concept_map String<std::string>
{
   //…
   std::string concatenate (std::string const& a, std::string const& b)
   {
      std::string tmp(a);
      return tmp += b;
   }
};


Damit lassen sich MyString und std::string für alle Algorithmen verwenden, die das String-Concept unterstützen, obwohl MyString und std::string zwei gänzlich unterschiedliche Schnittstellen anbieten.

Status - Oktober 2008
Concepts sind Teil des aktuellen Working Drafts.

Unterstützung
Keiner der größeren Compiler unterstützt dieses Feature. Es gibt allerdings eine angepasste Version der GCC, die concept und concept_map unterstützt: ConceptGCC.

Proposals
N2081 - Programmieren mit Concepts
N2398 - Voraussichtliche Formulierung


1.4 static_assert

Zur Überprüfung von Assertions stellte C++ bisher zwei Mechanismen zur Verfügung: Das Makro assert aus <cassert> und die #error-Direktive des Präprozessors.

Das Makro assert stellt dabei die Möglichkeit zur Verfügung, bestimmte Behauptungen zur Laufzeit zu überprüfen (z.B. Invarianten), die #error-Direktive hat schon vor der Kompilierung Auswirkungen.

Für die Template-Metaprogrammierung wird jedoch häufig noch eine zusätzliche Art von Assertion gebraucht, eine Art von Assertion, die zur Compile-Zeit selbst überprüft wird. Damit kann man unter anderem die Instanziierung eines Templates mit einem nicht adäquaten Typ verhindern und bekommt eine halbwegs lesbare Fehlermeldung. Solche so genannten Static-Assertions sind derart verbreitet, dass Boost beispielsweise ein eigenes Makro dafür anbietet: BOOST_STATIC_ASSERT. Die Fehlermeldungen, die davon generiert werden, sind jedoch oft nicht aussagekräftig genug, zumindest nicht so aussagekräftig, wie sie sein könnten.

Um statische Assertions einfacher zu machen, wurde das neue Schlüsselwort static_assert eingeführt.


Beispiel
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
1
2
3
4
5
6
7
8
9
10
11
#include <limits>
#include
<type_traits>

static_assert (std::numeric_limits<int>::digits >= 32, "fehler: int zu klein")


template <class Base, class Derived>
struct Foo
{
    static_assert (std::is_base_of<Base, Derived>::value, "fehler: Derived nicht von Base abgeleitet");
};
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
#include <limits>
#include
<type_traits>

static_assert (std::numeric_limits<int>::digits >= 32, "fehler: int zu klein")


template <class Base, class Derived>
struct Foo
{
static_assert (std::is_base_of<Base, Derived>::value, "fehler: Derived nicht von Base abgeleitet");
};
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
#include <limits>
#include
<type_traits>

static_assert (std::numeric_limits<int>::digits >= 32, "fehler: int zu klein")


template <class Base, class Derived>
struct Foo
{
    static_assert (std::is_base_of<Base, Derived>::value, "fehler: Derived nicht von Base abgeleitet");
};


Erläuterung
static_assert erwartet zwei Parameter: Einen konstanten Ausdruck und ein String-Literal.
Die Verwendung erklärt sich im Prinzip von selbst: Liefert der konstante Ausdruck true, hat die static_assert-Deklaration keinen Effekt. Andernfalls wird das Kompilieren abgebrochen. In diesem Fall ist der Compiler zwar nicht dazu verpflichtet, die Fehlermeldung, die im Stringliteral steht, auszugeben, wird jedoch dazu angehalten, dies zu tun. Eine static_assert-Deklaration kann überall dort vorkommen, wo es auch eine using-Deklaration darf.

Status - Juni 2008
Die static_assert-Deklaration ist bereits im derzeitigen Working-Draft des kommenden Standards enthalten.

Unterstützung
static_assert wird von GCC ab 4.3, Comeau ab 4.3.9 unterstützt.

Proposals
N1720 - Hintergrund, Verwendung, Formulierung


1.5 Über die neue Art, Funktionen zu deklarieren

Will man den Typ einer Variable in C++03 festlegen, so muss man dies explizit tun. Die einzige Möglichkeit, dies abzukürzen, stellen typedefs dar. Dies verwendet man beispielsweise in for-Schleifen wie der folgenden:

C/C++ Code:
typedef typename vector<T>::iterator iter;
for (iter i = v.begin(); …
C/C++ Code:
typedef typename vector<T>::iterator iter;
for (iter i = v.begin(); …
C/C++ Code:
typedef typename vector<T>::iterator iter;
for (iter i = v.begin(); …


In C++09 übernimmt das Schlüsselwort auto die automatische Bestimmung des Typs einer Variablen durch den Ausdruck, der sie initialisiert.

C/C++ Code:
auto x1 = 3.1415; //x ist double

int foo ();
auto x2 = foo();
auto const& x3 = foo(); //auto kann mit cv-Qualifizierern, * und & verwendet werden
C/C++ Code:
auto x1 = 3.1415; //x ist double

int foo ();
auto x2 = foo();
auto const& x3 = foo(); //auto kann mit cv-Qualifizierern, * und & verwendet werden
C/C++ Code:
auto x1 = 3.1415; //x ist double

int foo ();
auto x2 = foo();
auto const& x3 = foo(); //auto kann mit cv-Qualifizierern, * und & verwendet werden


Eine weitere Möglichkeit, den Typ eines bestimmten Ausdrucks zu bestimmen, bietet das neu eingeführte Schlüsselwort decltype an.

C/C++ Code:
1
2
3
4
5
6
7
8
9
1
2
3
4
5
6
7
8
9
int i;
double d;
int foo ();


decltype(i + i); //int
decltype(i * d); //double
decltype(foo()); //int
decltype(foo); //int()()
C/C++ Code:
1
2
3
4
5
6
7
8
9
int i;
double d;
int foo ();


decltype(i + i); //int
decltype(i * d); //double
decltype(foo()); //int
decltype(foo); //int()()
C/C++ Code:
1
2
3
4
5
6
7
8
9
int i;
double d;
int foo ();


decltype(i + i); //int
decltype(i * d); //double
decltype(foo()); //int
decltype(foo); //int()()


Eine der möglichen Verwendungen für decltype, die man bei dessen Entwicklung im Hinterkopf hatte, war die automatische Bestimmung des Rückgabetyps einer Funktion. Zunächst ein Beispiel, wie man eine Rückgabe-per-Parameter (als Referenz) mit decltype realisiert.

C/C++ Code:
template <class T, class U>
void add (T const& a, U const& b, decltype(a + b) & result);
C/C++ Code:
template <class T, class U>
void add (T const& a, U const& b, decltype(a + b) & result);
C/C++ Code:
template <class T, class U>
void add (T const& a, U const& b, decltype(a + b) & result);


Auch der Typ des Rückgabewerts einer Funktion sollte durch decltype automatisch hergeleitet werden. Allerdings stößt man hier auf ein Problem. Die angenehme Syntax, die eben noch möglich war, versagt, da die Parameter a und b noch nicht deklariert wurden:
C/C++ Code:
template <class T, class U>
decltype(a + b) //Fehler: Woher kommen a und b?
add (T const& a, U const& b); //Hier erst werden sie deklariert!
C/C++ Code:
template <class T, class U>
decltype(a + b) //Fehler: Woher kommen a und b?
add (T const& a, U const& b); //Hier erst werden sie deklariert!
C/C++ Code:
template <class T, class U>
decltype(a + b) //Fehler: Woher kommen a und b?
add (T const& a, U const& b); //Hier erst werden sie deklariert!


Die Lösung liegt in der zweiten großen Verwendungsmöglichkeit des Schlüsselwortes auto.
Das alles kombiniert erfordert allerdings die Verwendung einer neuen Art von Funktionsdeklaration.


Beispiel - Funktionsdeklaration in C++09
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
template <class T, class U>
auto operator+ (T const& a, U const& b) -> decltype(a + b);

//Dies ist _nicht_ auf Templates beschränkt.
auto foo () -> int;

class Bar
{
   auto quux () const throw () -> int;
};

//Damit werden typedefs und Funktionszeiger auch einfacher zu handhaben:
typedef (auto (int) -> int) F;
F foo; //äquivalent zu int foo (int);

typedef (auto (double) -> double) * PF; //Zeiger auf Funktion

(auto (int) -> int)* a[10]; //Array von Funktionszeigern

//Zeiger auf Funktion, die einen Funktionszeiger zurückgibt:

typedef (auto (int) -> (auto (double) -> double) *) *PFF;
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
template <class T, class U>
auto operator+ (T const& a, U const& b) -> decltype(a + b);

//Dies ist _nicht_ auf Templates beschränkt.
auto foo () -> int;

class Bar
{
auto quux () const throw () -> int;
};

//Damit werden typedefs und Funktionszeiger auch einfacher zu handhaben:
typedef (auto (int) -> int) F;
F foo; //äquivalent zu int foo (int);

typedef (auto (double) -> double) * PF; //Zeiger auf Funktion

(auto (int) -> int)* a[10]; //Array von Funktionszeigern

//Zeiger auf Funktion, die einen Funktionszeiger zurückgibt:

typedef (auto (int) -> (auto (double) -> double) *) *PFF;
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
template <class T, class U>
auto operator+ (T const& a, U const& b) -> decltype(a + b);

//Dies ist _nicht_ auf Templates beschränkt.
auto foo () -> int;

class Bar
{
   auto quux () const throw () -> int;
};

//Damit werden typedefs und Funktionszeiger auch einfacher zu handhaben:
typedef (auto (int) -> int) F;
F foo; //äquivalent zu int foo (int);

typedef (auto (double) -> double) * PF; //Zeiger auf Funktion

(auto (int) -> int)* a[10]; //Array von Funktionszeigern

//Zeiger auf Funktion, die einen Funktionszeiger zurückgibt:

typedef (auto (int) -> (auto (double) -> double) *) *PFF;


Erläuterung
Ursprünglich für den Einsatz mit decltype bei der automatischen Bestimmung des Rückgabetyps einer Funktion gedacht, bringt diese neue Art, Funktionen zu deklarieren, Vorteile vor allem in der Lesbarkeit.

Status - Oktober 2008
Alle genannten Features sind bereits im Working-Draft integriert.
Im Komitee gab es eine Debatte, ob die neue Funktionsdeklaration sich syntaktisch mehr an Lambda-Funktionen orientieren soll, also ob sie aussehen soll, wie folgt:
C/C++ Code:
[] foo () -> int
{
  ...
}
C/C++ Code:
[] foo () -> int
{
...
}
C/C++ Code:
[] foo () -> int
{
  ...
}

Dieser Vorschlag wurde zwar abgelehnt, dennoch soll die Option offenbleiben, nach ausführlicheren Diskussionen die Syntax hierhingehend umzubauen.

Unterstützung
decltype wird von GCC ab 4.3. unterstützt. auto mit der neuen Funktion wird durch den Comeau-Compiler unterstützt. Die Funktionsdeklaration mit der neuen Syntax wird meines Wissens nach noch von keinem Compiler angeboten.

Proposals
N1979 - Erläuterungen zu decltype und der neuen Funktionsdeklaration
N1984 - automatische Typherleitung (auto)



1.6. Lambda-Ausdrücke

Viele Programmiersprachen, vor allem viele funktionale Programmiersprachen, unterstützen es, lokale, namenlose Funktionen on-the-fly innerhalb einer Funktion zu definieren. Diese Funktionen haben verschiedene Einsatzmöglichkeiten: Beispielsweise könnten Funktionen höherer Ordnung wie for_each unter C++ mit ihnen arbeiten. Im Moment wäre for_each noch auf einen Funktor oder eine Funktion angewiesen, die extra angelegt und benannt werden müsste. Solche Funktionen, die on-the-fly erstellt werden können, nennt man Lambda-Funktionen, manchmal auch Closures.

Mit C++09 könnte sich das ändern. Ein Lambda-Ausdruck (bzw. eine Lambda-Funktion) in C++09 spezifiziert ein anonymes Funktionsobjekt. "Closure" ist die Bezeichnung für das danach erstellte Funktionsobjekt. Closures beinhalten neben der eigentlichen Funktion noch Kopien von Variablen aus dem Sichtbarkeitsbereich, in dem die anonyme Funktion vorkommt, während "reine" Lambda-Objekte mit Referenzen auf Variablen, die außerhalb stehen arbeiten. Außerdem ist ein "Mix" von Closures und Lambda-Funktionen vorgesehen, so dass man für einzelne Variablen selbst festlegen kann, ob die anonyme Funktion mit Kopien oder Referenzen arbeiten soll.

Lambda-Ausdrücke bauen auf der neuen Art, Funktionen zu deklarieren (siehe 1.5) auf.


Beispiel
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//Eins: anonyme Funktion als "Single-Expression"
int i = [](int x, int y) (x + y) (42, 23);

//Zwei: In der "Funktionsblock"-Version:
int j = [](int x, int y) -> int { int z; z = x + y; return z; } (1, 2);


//Drei:
int array [] = { 1, 2, 3, 4 };
int sum = 0;

//Bildet die Funktionalität von std::accumulate nach, expliziter Zugriff auf sum:
for_each (array, array+4, [&sum](int element) (sum += element));

//Vier: Zugriff auf alle Variablen aus dem Scope des
//Lambda-Ausdrucks via Referenz

for_each (array, array+4, [&](int element) (sum += element));

//Fünf: Zugriff auf alle Variablen aus dem Scope des Lambda-Ausdrucks
//als Kopie (wird als non-const/volatile Membervariable des Closures
//realisiert)

int sumsum = [=]()(return sum + sum);

//Sechs: Zugriff auf alle Variablen aus dem Scope des Lambda-Ausdrucks
//als Kopie, aber mit einer Referenz auf sum:

int quux = [=, &sum] () (return sum *= 2);
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//Eins: anonyme Funktion als "Single-Expression"
int i = [](int x, int y) (x + y) (42, 23);

//Zwei: In der "Funktionsblock"-Version:
int j = [](int x, int y) -> int { int z; z = x + y; return z; } (1, 2);


//Drei:
int array [] = { 1, 2, 3, 4 };
int sum = 0;

//Bildet die Funktionalität von std::accumulate nach, expliziter Zugriff auf sum:
for_each (array, array+4, [&sum](int element) (sum += element));

//Vier: Zugriff auf alle Variablen aus dem Scope des
//Lambda-Ausdrucks via Referenz

for_each (array, array+4, [&](int element) (sum += element));

//Fünf: Zugriff auf alle Variablen aus dem Scope des Lambda-Ausdrucks
//als Kopie (wird als non-const/volatile Membervariable des Closures
//realisiert)

int sumsum = [=]()(return sum + sum);

//Sechs: Zugriff auf alle Variablen aus dem Scope des Lambda-Ausdrucks
//als Kopie, aber mit einer Referenz auf sum:

int quux = [=, &sum] () (return sum *= 2);
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//Eins: anonyme Funktion als "Single-Expression"
int i = [](int x, int y) (x + y) (42, 23);

//Zwei: In der "Funktionsblock"-Version:
int j = [](int x, int y) -> int { int z; z = x + y; return z; } (1, 2);


//Drei:
int array [] = { 1, 2, 3, 4 };
int sum = 0;

//Bildet die Funktionalität von std::accumulate nach, expliziter Zugriff auf sum:
for_each (array, array+4, [&sum](int element) (sum += element));

//Vier: Zugriff auf alle Variablen aus dem Scope des
//Lambda-Ausdrucks via Referenz

for_each (array, array+4, [&](int element) (sum += element));

//Fünf: Zugriff auf alle Variablen aus dem Scope des Lambda-Ausdrucks
//als Kopie (wird als non-const/volatile Membervariable des Closures
//realisiert)

int sumsum = [=]()(return sum + sum);

//Sechs: Zugriff auf alle Variablen aus dem Scope des Lambda-Ausdrucks
//als Kopie, aber mit einer Referenz auf sum:

int quux = [=, &sum] () (return sum *= 2);


Erläuterung
Lambda-Ausdrücke sollen vom Compiler in normale Funktionsobjekte übersetzt werden. Aus dem ersten Lambda-Ausdruck (Eins) in unserem Beispiel soll vom Compiler ein Code erzeugt werden, der so oder so ähnlich aussieht:

C/C++ Code:
struct lambda_1
{
   int operator () (int x, int y) { return x + y; }
}
int i = lambda_1()(42,23);
C/C++ Code:
struct lambda_1
{
int operator () (int x, int y) { return x + y; }
}
int i = lambda_1()(42,23);
C/C++ Code:
struct lambda_1
{
   int operator () (int x, int y) { return x + y; }
}
int i = lambda_1()(42,23);


Die Möglichkeit, der Lambda-Funktion Variablen aus dem aktuellen Scope mitzugeben (Beispiel Drei), wird durch die spezielle Syntax mit einem Doppelpunkt [&referenz, kopie](int argument) ermöglicht. Alles, was zwischen den runden Klammern steht, sind die Parameter der Lambda-Funktion, auf alle Variablen in der Closure-Liste zwischen den eckigen Klammern kann das Closure entweder direkt (als Referenz mit dem & davor) oder als Kopie (ohne & zugreifen. Man kann sich dies so vorstellen, dass der Compiler dem Konstruktor des Funktionsobjekts Referenzen bzw. Kopien lokaler Variablen mitgibt.

C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
1
2
3
4
5
6
7
8
9
10
11
int a;

//Zugriff auf a als Referenz
[&]() { a = 42; }
//Gleichbedeutend mit
[&a]() { a = 42; }

//Zugriff auf a als Kopie
[=]() { cout << a << endl; }
//Gleichbedeutend mit
[a]() { cout << a << endl; }
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
int a;

//Zugriff auf a als Referenz
[&]() { a = 42; }
//Gleichbedeutend mit
[&a]() { a = 42; }

//Zugriff auf a als Kopie
[=]() { cout << a << endl; }
//Gleichbedeutend mit
[a]() { cout << a << endl; }
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
int a;

//Zugriff auf a als Referenz
[&]() { a = 42; }
//Gleichbedeutend mit
[&a]() { a = 42; }

//Zugriff auf a als Kopie
[=]() { cout << a << endl; }
//Gleichbedeutend mit
[a]() { cout << a << endl; }


Closures sind dann nützlich, wenn man eine Lambda-Funktion außerhalb des Scopes verwendet, in dem sie definiert wurde. Damit lassen sich Closures also Problemlos von Funktionen zurückgeben.

Status - Juni 2008
Alle hier besprochenen Features sind Teil des Working-Drafts.


Unterstützung
Mir sind keine C++-Compiler bekannt, die Lambda-Funktionen unterstützen.

Proposals
N2413 - Erläuterungen und Beispiele
N2550 - Final Wording

1.7. Neue Literale

Die grundlegende Einheit im Speichermodell von C++ ist das Byte.
ANSI ISO IEC 14882:2003 schrieb:

A byte is at least large enough to contain any member of the basic execution character set and is composed of a contiguous sequence of bits, the number of which is implementation-defined.


Der neue Standard erweitert diese Definition und schreibt vor, dass ein Byte zumindest auch jene 8-Bit Einheiten von UTF-8 unterstützen soll.

String-Literale sind Zeichensequenzen, die von hochgestellten doppelten Anführungszeichen umschlossen sind, also beispielsweise "Quux" und "Fubar". C++03 stellt zwei Arten von String-Literalen zur Verfügung: Normale String-Literale und Wide-String-Literale. Erstere sind vom Typ "Array von n const char", letztere vom Typ "Array von n const wchar_t". Wide-String-Literale werden durch ein "L" als Präfix gekennzeichnet.

C/C++ Code:
"Quux"; //String-Literal
L"Bar"; //Wide-String-Literal
C/C++ Code:
"Quux"; //String-Literal
L"Bar"; //Wide-String-Literal
C/C++ Code:
"Quux"; //String-Literal
L"Bar"; //Wide-String-Literal


C++09 führt einige neue Arten von String-Literalen ein.


  • UTF-8-String-Literale. Diese beginnen mit dem Präfix u8. Die Zeichen, die es beinhaltet, sind UTF-8-kodiert. Da ein einzelnes UTF-8-kodiertes Byte in einem gewöhnlichen char gespeichert werden kann, sind UTF-8-kodierte String-Literale vom Typ "Array von n const char".
  • UTF-16-String-Literale. Eingeleitet werden diese mit dem Präfix u. Die dahinterstehende Kodierung ist UTF-16 und der Typ der Literale ist "Array von n const char16_t". char16_t ist ein neu eingeführter Typ mit der Kodierung UTF-16, der im Header <cuchar> definiert ist.
  • UTF-32-String-Literale. Sie beginnen mit einem U. Die Kodierung ist UTF-32 und der Typ ist "Array von n const char32_t". char32_t ist ebenfalls in <cuchar> definiert.
  • Rohe String-Literale. Zu jeder der aufgeführten Arten gibt es korrespondierende "rohe" String-Literale, die vor allem den Umgang mit Regular-Expressions vereinfachen sollen. Innerhalb solcher Literale ist es nicht notwendig, einen Schrägstrich oder Anführungszeichen zu escapen. Diese String-Literale enthalten in ihrem Präfix ein "R", also entweder LR, u8R, uR, UR oder nur R.



Beispiel 1 - Neue String-Literale
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
char const* ordinary_literal = "Next comes the realist phase";
char const* utf8_literal = u8"After all,";
wchar_t const* wide_char_literal = L"from a purely geometrical point of
view";

char16_t const* utf16_literal = u"a cat is only a tube";
char32_t const* utf32_literal = u"with a door at the top.";

char const* raw_literal = R"[by
"Terry Pratchett"
]";

assert(strcmp(raw_literal, "by\n\"Terry Pratchett\"") == 0);

char const* raw_utf8 = u8R"**[...]**";
char16_t const* raw_utf16 = uR"*@[...]@*";
char32_t const* raw_utf32 = UR"zzz[...]zzz";
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
char const* ordinary_literal = "Next comes the realist phase";
char const* utf8_literal = u8"After all,";
wchar_t const* wide_char_literal = L"from a purely geometrical point of
view";

char16_t const* utf16_literal = u"a cat is only a tube";
char32_t const* utf32_literal = u"with a door at the top.";

char const* raw_literal = R"[by
"Terry Pratchett"
]";

assert(strcmp(raw_literal, "by\n\"Terry Pratchett\"") == 0);

char const* raw_utf8 = u8R"**[...]**";
char16_t const* raw_utf16 = uR"*@[...]@*";
char32_t const* raw_utf32 = UR"zzz[...]zzz";
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
char const* ordinary_literal = "Next comes the realist phase";
char const* utf8_literal = u8"After all,";
wchar_t const* wide_char_literal = L"from a purely geometrical point of
view";

char16_t const* utf16_literal = u"a cat is only a tube";
char32_t const* utf32_literal = u"with a door at the top.";

char const* raw_literal = R"[by
"Terry Pratchett"
]";

assert(strcmp(raw_literal, "by\n\"Terry Pratchett\"") == 0);

char const* raw_utf8 = u8R"**[...]**";
char16_t const* raw_utf16 = uR"*@[...]@*";
char32_t const* raw_utf32 = UR"zzz[...]zzz";


Erläuterung
Vor allem rohe String-Literale bieten einiges an Neuerungen: Sie beginnen nicht einfach mit doppelten Anführungszeichen, ihr eigentlicher Inhalt ist zwischen zwei eckigen Klammern. Innerhalb dieser eckigen Klammern müssen Zeichen wie der Backslash und Anführungszeichen nicht durch einen Backslash eingeleitet werden.

C/C++ Code:
R"[The Great Zaganza said: "You are very fat and stupid and
persistently wear a ridiculous hat which you should be ashamed of."]";
C/C++ Code:
R"[The Great Zaganza said: "You are very fat and stupid and
persistently wear a ridiculous hat which you should be ashamed of."]";
C/C++ Code:
R"[The Great Zaganza said: "You are very fat and stupid and
persistently wear a ridiculous hat which you should be ashamed of."]";

Merke: Innerhalb von "[ und ]" müssen die Anführungszeichen in der direkten Rede nicht als \" eingegeben werden. Newlines in der Quelldatei werden eins-zu-eins im String-Literal nachgebildet. Das kann man allerdings mit einem Backslash am Ende der Zeile, ganz so wie bei Makros, verhindern.

Um die Verwendung zu vereinfachen, ist es außerdem möglich, zwischen " und [ bis zu 16 Zeichen zu setzen. Damit lässt sich ein rohes String-Literal auch wie folgt schreiben.

C/C++ Code:
u8R"-->[Der Inhalt]-->";
C/C++ Code:
u8R"-->[Der Inhalt]-->";
C/C++ Code:
u8R"-->[Der Inhalt]-->";


Folgender String kann mit Hilfe roher String-Literale einfacher ausgedrückt werden
Beispiel 3 - HTML in String-Literalen
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
"<HTML>\n"
"<HEAD>\n"
"<TITLE>Auto-generated html formated source</TITLE>\n"
"<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=windows-1252\">\n"
"</HEAD>\n"
"<BODY LINK=\"#0000ff\" VLINK=\"#800080\" BGCOLOR=\"#ffffff\">\n"
"<P> </P>\n"
"<PRE>\n"

//Mit einem rohen String-Literal sieht das ganze so aus:
R"[\
<HTML>
<HEAD>
<TITLE>Auto-generated html formated source</TITLE>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
</HEAD>
<BODY LINK="#0000ff" VLINK="#800080" BGCOLOR="#ffffff">
<P> </P>
<PRE>
]"
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
"<HTML>\n"
"<HEAD>\n"
"<TITLE>Auto-generated html formated source</TITLE>\n"
"<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=windows-1252\">\n"
"</HEAD>\n"
"<BODY LINK=\"#0000ff\" VLINK=\"#800080\" BGCOLOR=\"#ffffff\">\n"
"<P> </P>\n"
"<PRE>\n"

//Mit einem rohen String-Literal sieht das ganze so aus:
R"[\
<HTML>
<HEAD>
<TITLE>Auto-generated html formated source</TITLE>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
</HEAD>
<BODY LINK="#0000ff" VLINK="#800080" BGCOLOR="#ffffff">
<P> </P>
<PRE>
]"
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
"<HTML>\n"
"<HEAD>\n"
"<TITLE>Auto-generated html formated source</TITLE>\n"
"<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=windows-1252\">\n"
"</HEAD>\n"
"<BODY LINK=\"#0000ff\" VLINK=\"#800080\" BGCOLOR=\"#ffffff\">\n"
"<P> </P>\n"
"<PRE>\n"

//Mit einem rohen String-Literal sieht das ganze so aus:
R"[\
<HTML>
<HEAD>
<TITLE>Auto-generated html formated source</TITLE>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
</HEAD>
<BODY LINK="#0000ff" VLINK="#800080" BGCOLOR="#ffffff">
<P> </P>
<PRE>
]"


Der Sinn der Zeichenkette zwischen " und [ liegt darin, dass man sich jegliche Escape-Sequenzen erspart. Man stelle sich einen String vor, der die Zeichenfolge ]" beinhalten soll. Mit rohen String-Literalen kein Problem:
C/C++ Code:
R"--[Dieser String kann über ]" sprechen]--";
C/C++ Code:
R"--[Dieser String kann über ]" sprechen]--";
C/C++ Code:
R"--[Dieser String kann über ]" sprechen]--";

Will man nun über ]" und ]--" sprechen, ist das dank dieser Zeichenkette ebenfalls möglich:
C/C++ Code:
R"-*-[Dieser String spricht über ]" und ]--" als wäre nichts]-*-";
C/C++ Code:
R"-*-[Dieser String spricht über ]" und ]--" als wäre nichts]-*-";
C/C++ Code:
R"-*-[Dieser String spricht über ]" und ]--" als wäre nichts]-*-";


Neben String-Literalen gibt es in C++ auch Ganzzahl- und Gleitkommazahl-Literale, beispielsweise ist 1024L mit dem Suffix "L" automatisch vom Typ long int. Es wird in C++09 eventuell möglich sein, auch selbstdefinierte Suffixe für eigene Literale zu erschaffen. Damit ist zum Beispiel die Implementierung einer Ganzzahlklasse möglich, die beliebig große Zahlen aufnehmen kann.


Beispiel 3 - Selbstdefinierte Literale
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
1
2
3
4
5
6
7
8
9
10
11
12
13
//So etwas wäre möglich:
123.4567890123df //dezimale Gleitkommazahl (realisiert in Klasse DecimalFloat)
"hello!"s        //std::string
3.4i             //std::complex

10110101b        //binäre Zahl
123km            //Kilometer
54385839210349381058031481309349031big
                 //Zahl mit beliebigen Bereich
                   
unsigned long operator "b" (char const*);

template <char...> unsigned long operator "bb" ();
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
//So etwas wäre möglich:
123.4567890123df //dezimale Gleitkommazahl (realisiert in Klasse DecimalFloat)
"hello!"s //std::string
3.4i //std::complex

10110101b //binäre Zahl
123km //Kilometer
54385839210349381058031481309349031big
//Zahl mit beliebigen Bereich

unsigned long operator "b" (char const*);

template <char...> unsigned long operator "bb" ();
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
//So etwas wäre möglich:
123.4567890123df //dezimale Gleitkommazahl (realisiert in Klasse DecimalFloat)
"hello!"s        //std::string
3.4i             //std::complex

10110101b        //binäre Zahl
123km            //Kilometer
54385839210349381058031481309349031big
                 //Zahl mit beliebigen Bereich
                   
unsigned long operator "b" (char const*);

template <char...> unsigned long operator "bb" ();


Erläuterung
T operator "X" (char const*) ist ein Literal-Operator. In obigem Beispiel ist unsigned long operator "b" (char const*) einer. Dieser Operator wird aufgerufen mit 10110101b; - das wird übersetzt in folgenden Funktionsaufruf:
C/C++ Code:
operator "b"("10110101");
C/C++ Code:
operator "b"("10110101");
C/C++ Code:
operator "b"("10110101");


Zusätzlich gibt es eine Literal-Operatoren-Form, die auf Variadic Templates basiert. Im Beispielcode ist operator "bb" auf diese Weise implementiert. Dieser Operator wird wie folgt aufgerufen:
C/C++ Code:
1234bb;
//wird zu
operator "bb" <'1', '2', '3', '4'> ()
C/C++ Code:
1234bb;
//wird zu
operator "bb" <'1', '2', '3', '4'> ()
C/C++ Code:
1234bb;
//wird zu
operator "bb" <'1', '2', '3', '4'> ()

In Kombination mit constexpr erlaubt dies die Zusammensetzung von Werten zur Compile-Zeit.

Status - Oktober 2008
Sowohl die neuen String-Literale als auch die Möglichkeit, selbst Literale zu definieren, sind Teil des aktuellen Working-Drafts.

Unterstützung
Mir sind keine Compiler bekannt, die dieses Feature unterstützen.

Proposals
N2146 - Rohe String-Literale (Beispiele)
N2209 - UTF-8-String-Literale (Beipsiele)
N2442 - Unified Proposal
N2249 - Neue primitive Typen
N2378 - Selbstdefinierbare Literale

2 Bewährtes verbessert

Einige der bestehenden Sprachmöglichkeiten werden durch den neuen Standard so erweitert, dass sie entweder einfacher einzusetzen (die neue for-Schleife, right-angle-brackets, …), aussagekräftiger (deleted-Funktionen statt private Copy-Konstruktoren, konstante Ausdrücke, nullptr statt NULL, …) oder typsicher (enums und nullptr) sind, oder so dass ihre Semantik auf andere Sprachkonstrukte ausgedehnt wird (template-Aliases, explizite Umwandlungsoperatoren, …).


2.1 Templates neu

Im Bereich der generischen Programmierung hat sich einiges getan. Die bereits erwähnten Variadic Templates (1.1) machen dabei sicher einen großen Teil aus, aber sind bei weitem nicht alles.

Zu den Verbesserungen, die Templates betreffen, gehören:

  • Template Aliases (aka Template Typedefs). Erlaubt das Einführen von typedef-Namen über eine so genannte alias-Deklaration mithilfe von using.
  • Extern Template. Verhindert die (implizite) Instanziierung eines Templates. Die Instanziierung muss in einer anderen Übersetzungseinheit stattfinden.
  • Erweiterte friend-Deklaration. Erlaubt die Deklaration friend class T; innerhalb eines Templates mit dem Template-Parameter T.
  • Right Angle Brackets. >> wird im Kontext von Templates nicht mehr als Right-Shift-Operator interpretiert.
  • Default-Templateargumente für Funktionstemplates.



Beispiel
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
using foo = int;                   //Alias-Deklaration.

template <class T, class U>
struct Foo;

template <class T>
using SameFoo = Foo<T, T>;

SameFoo<int> x;                    //Identisch zu Foo<int, int>.

//Verhindert die implizierte Instanziierung von
//Foo<double, int> in dieser Übersetzungseinheit

extern template Foo<double, int>;

void take_foo (Foo<double, int> foo)
{
//Foo<double, int> wird hier nicht instanziiert.
}

#include
<vector>

void bar ()
{
   vector<vector<int>> vvi;         //Beachte: Kein Abstand zwischen > und >
}

template <class T = int>            //Nicht legal in C++03
void quux (T t) {}

template <class T>
class no_children
{
   no_children () {}
   friend class T;                  //Nicht legal in C++03
};

class bachelorette
: virtual no_children<bachelorette> //eine "final"-class in C++09
{
   friend Foo;                      //friend class Foo ist nicht nötig
   friend class girlfriend;         //Vorwärtsdeklaration inklusive
};

class girlfriend                    //Hat Zugriff auf alle privaten Daten von bachelorette
{
};
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
using foo = int; //Alias-Deklaration.

template <class T, class U>
struct Foo;

template <class T>
using SameFoo = Foo<T, T>;

SameFoo<int> x; //Identisch zu Foo<int, int>.

//Verhindert die implizierte Instanziierung von
//Foo<double, int> in dieser Übersetzungseinheit

extern template Foo<double, int>;

void take_foo (Foo<double, int> foo)
{
//Foo<double, int> wird hier nicht instanziiert.
}

#include
<vector>

void bar ()
{
vector<vector<int>> vvi; //Beachte: Kein Abstand zwischen > und >
}

template <class T = int> //Nicht legal in C++03
void quux (T t) {}

template <class T>
class no_children
{
no_children () {}
friend class T; //Nicht legal in C++03
};

class bachelorette
: virtual no_children<bachelorette> //eine "final"-class in C++09
{
friend Foo; //friend class Foo ist nicht nötig
friend class girlfriend; //Vorwärtsdeklaration inklusive
};

class girlfriend //Hat Zugriff auf alle privaten Daten von bachelorette
{
};
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
using foo = int;                   //Alias-Deklaration.

template <class T, class U>
struct Foo;

template <class T>
using SameFoo = Foo<T, T>;

SameFoo<int> x;                    //Identisch zu Foo<int, int>.

//Verhindert die implizierte Instanziierung von
//Foo<double, int> in dieser Übersetzungseinheit

extern template Foo<double, int>;

void take_foo (Foo<double, int> foo)
{
//Foo<double, int> wird hier nicht instanziiert.
}

#include
<vector>

void bar ()
{
   vector<vector<int>> vvi;         //Beachte: Kein Abstand zwischen > und >
}

template <class T = int>            //Nicht legal in C++03
void quux (T t) {}

template <class T>
class no_children
{
   no_children () {}
   friend class T;                  //Nicht legal in C++03
};

class bachelorette
: virtual no_children<bachelorette> //eine "final"-class in C++09
{
   friend Foo;                      //friend class Foo ist nicht nötig
   friend class girlfriend;         //Vorwärtsdeklaration inklusive
};

class girlfriend                    //Hat Zugriff auf alle privaten Daten von bachelorette
{
};


Status - Juni 2008
Alle diese Features sind bereits im Working-Draft des kommenden C++-Standards enthalten.

Unterstützung
Comeau unterstützt die erweiterte friend-Deklaration, GCC 4.3. unterstützt Right Angle Brackets und Default-Templateargumente für Funktionstemplates.
Comeau, Borland C++, GCC, IBM, Metrowerks, Microsofts C++ Compiler unterstützen bereits alle extern-Templates.

Proposals
N1489 - Alias-Deklarationen (Hintergrund)
N1448 - Extern Templates (Hintergrund)
N1520 - Erweiterte friend-Deklaration (Hintergrund)
N1757 - Right-Angle-Brackets


2.2 Konstruktion von Objekten

Neben der bereits angeführten Möglichkeit, Konstruktoren einzuführen, die die Move-Semantik (1.2) unterstützen, gibt es einiges Neues bei Elementinitialisierungslisten und der Art, wie Konstruktoren aufgerufen werden können.

  • Delegierte Konstruktoren. Es ist nun möglich, Konstruktoren aus anderen Konstruktoren aufzurufen.
  • Forward Constructors. Vorwärtskonstruktoren (vererbte Konstruktoren) geben ihre Argumente direkt an die entsprechenden Konstruktoren der Basisklasse weiter.
  • Einheitliche Initialisierung. Die Syntax für die Initialisierung von Arrays wird ausgeweitet.
  • std::initializer_list<...> - Initialisierungslisten auch für komplexe Klassen.
  • Direkte Initialisierung von nicht-statischen, nicht-konstanten Klassenvariablen


Beispiel
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
class Foo
{
   int a = 42;                    //direkte Initialisierung nicht-statischer,
   int b = 23;                    //nicht-konstanter Elementariablen und
   int array[] = { 1, 2, 3 };     //sogar von Arrays!
   
public:
   Foo ()
   : a(12), array{ 4, 5, 6 } {}   //a = 12, b = 23, array = { 4, 5, 6 }
   Foo (int x) : a(x) {}          //a = x, b = 23
   Foo (int x, int y)
   : a{x}, b{y} {}                //einheitliche Initialisierung mit {}
};

#include
<initializer_list>

class Bar : public Foo
{
public:
   //Vorwärtskonstruktoren:
   using default Foo;             //Deklariert Bar(), Bar(int) und Bar(int, int);
   
   Bar (std::initializer_list<int> list)
   {
      //Compiler-Magie: list.size() ist als constexpr deklariert (siehe 2.3)
      int elems[list.size()];    
      std::copy (list.begin(), list.end(), elems);
   }
};

Bar b = { 1, 2, 3, 4, 5 };        //Verwende die std::initializer_list

Bar foo (Bar b)
{
   return { 10, 11, 12, 13, 14 };
}

foo( {6,7,8,9} );                  


#include
<vector>

int main ()
{
   //Auch std::vector unterstützt std::initializer_list
   std::vector<Bar> v
   {
      { 1, 2, 3, 4 },
      { 5, 6, 7 },
      { 8, 9 }
   };
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
class Foo
{
int a = 42; //direkte Initialisierung nicht-statischer,
int b = 23; //nicht-konstanter Elementariablen und
int array[] = { 1, 2, 3 }; //sogar von Arrays!

public:
Foo ()
: a(12), array{ 4, 5, 6 } {} //a = 12, b = 23, array = { 4, 5, 6 }
Foo (int x) : a(x) {} //a = x, b = 23
Foo (int x, int y)
: a{x}, b{y} {} //einheitliche Initialisierung mit {}
};

#include
<initializer_list>

class Bar : public Foo
{
public:
//Vorwärtskonstruktoren:
using default Foo; //Deklariert Bar(), Bar(int) und Bar(int, int);

Bar (std::initializer_list<int> list)
{
//Compiler-Magie: list.size() ist als constexpr deklariert (siehe 2.3)
int elems[list.size()];
std::copy (list.begin(), list.end(), elems);
}
};

Bar b = { 1, 2, 3, 4, 5 }; //Verwende die std::initializer_list

Bar foo (Bar b)
{
return { 10, 11, 12, 13, 14 };
}

foo( {6,7,8,9} );


#include
<vector>

int main ()
{
//Auch std::vector unterstützt std::initializer_list
std::vector<Bar> v
{
{ 1, 2, 3, 4 },
{ 5, 6, 7 },
{ 8, 9 }
};
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
class Foo
{
   int a = 42;                    //direkte Initialisierung nicht-statischer,
   int b = 23;                    //nicht-konstanter Elementariablen und
   int array[] = { 1, 2, 3 };     //sogar von Arrays!
   
public:
   Foo ()
   : a(12), array{ 4, 5, 6 } {}   //a = 12, b = 23, array = { 4, 5, 6 }
   Foo (int x) : a(x) {}          //a = x, b = 23
   Foo (int x, int y)
   : a{x}, b{y} {}                //einheitliche Initialisierung mit {}
};

#include
<initializer_list>

class Bar : public Foo
{
public:
   //Vorwärtskonstruktoren:
   using default Foo;             //Deklariert Bar(), Bar(int) und Bar(int, int);
   
   Bar (std::initializer_list<int> list)
   {
      //Compiler-Magie: list.size() ist als constexpr deklariert (siehe 2.3)
      int elems[list.size()];    
      std::copy (list.begin(), list.end(), elems);
   }
};

Bar b = { 1, 2, 3, 4, 5 };        //Verwende die std::initializer_list

Bar foo (Bar b)
{
   return { 10, 11, 12, 13, 14 };
}

foo( {6,7,8,9} );                  


#include
<vector>

int main ()
{
   //Auch std::vector unterstützt std::initializer_list
   std::vector<Bar> v
   {
      { 1, 2, 3, 4 },
      { 5, 6, 7 },
      { 8, 9 }
   };
}


Erläuterung
std::vector kann in Kombination mit std::initializer_list letzten Endes wie ein herkömmliches Array verwendet werden. Womöglich wird sich die einheitliche Form, Variablen zu initialisieren - int a { 5 }; - wegen ihrer Uniformität durchsetzen.

Status - Oktober 2008
Alle hier vorgestellten Konstrukte sind Teil des aktuellen Working-Drafts.

Unterstützung
Mir sind keine Compiler bekannt, die diese Features unterstützen.

Proposals
N2215 - einheitliche Initialisierung und Initialisierungslisten (Hintergründe)
N1986 - Delegierte Konstruktoren
N2376 - Vererbte Konstruktoren


2.3 Konstante Ausdrücke

Konstante Ausdrücke in C++ sind Ausdrücke, die bereits zur Compile-Zeit ausgewertet werden. Konstante Ausdrücke können beispielsweise bei der Definition eines nicht-dynamischen Arrays verwendet werden. Ein Drawback ist, dass C++03 vorschreibt, dass ein Ausdruck, in dem eine Funktion aufgerufen wird, kein konstanter mehr ist. C++09 ändert diesen Sachverhalt: Wird eine Funktion mit dem Schlüsselwort constexpr deklariert, kann sie dennoch als Teil eines konstanten Ausdrucks verwendet werden.


Beispiel
C/C++ Code:
const int size = 42;
int array1[size];

constexpr int square (int x) { return x*x; }
int array2[square(4)];
C/C++ Code:
const int size = 42;
int array1[size];

constexpr int square (int x) { return x*x; }
int array2[square(4)];
C/C++ Code:
const int size = 42;
int array1[size];

constexpr int square (int x) { return x*x; }
int array2[square(4)];


Erläuterung
Vor allem Funktionen wie numeric_limits<T>::max() können nun in konstanten Ausdrücken verwendet werden.
Damit eine Funktion in einem konstanten Ausdruck vorkommen kann, …

  • … muss sie als constexpr deklariert werden,
  • … darf sie nur ein return expr; Statement enthalten,
  • … darf sie nur bereits vollständig definierte Funktionen aufrufen (d.h. nicht sich selbst).


Status - Juni 2008
Dieses Feature ist bereits Teil des Working-Drafts für den kommenden C++-Standard.

Unterstützung
Meines Wissens wird dieses Feature noch von keinem Compiler unterstützt.

Proposals
N2235 - Konstante Ausdrücke (Hintergründe)


2.4 for für Ranges

Oftmals muss man mit einer for-Schleife einen Bereich [begin, end[ durchgehen. Dies geschieht meist mit Iteratoren, deren Definition in for-Schleifen schon durch das Schlüsselwort auto vereinfacht wurde. Mithilfe von Concepts (1.3) ist es jetzt auch möglich, die Semantik einer neuen for-Schleife zu beschreiben, die über einen bestimmten Bereich iteriert.

Das Concept "Range" ist in <iterator_concept> wie folgt definiert:
C/C++ Code:
concept Range <typename T>
{
   typedef InputIterator iterator;
   iterator begin (T&);
   iterator end (T&);
};
C/C++ Code:
concept Range <typename T>
{
typedef InputIterator iterator;
iterator begin (T&);
iterator end (T&);
};
C/C++ Code:
concept Range <typename T>
{
   typedef InputIterator iterator;
   iterator begin (T&);
   iterator end (T&);
};

Für Arrays, die Standardcontainer und std::initializer_list sind jeweils concept_maps definiert, die es erlauben, sie als Range zu betrachten.


Beispiel - Anwendung der neuen for-Schleife
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
#include <iterator_concept>

template <class T>
void test (T range)
{
   for (auto& element: range)
   {                          
      element *= 2;
   }
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
#include <iterator_concept>

template <class T>
void test (T range)
{
for (auto& element: range)
{
element *= 2;
}
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
#include <iterator_concept>

template <class T>
void test (T range)
{
   for (auto& element: range)
   {                          
      element *= 2;
   }
}


Erläuterung
Die Variable range muss das Concept Range unterstützen (oder es muss eine passende Concept-Map bereitgestellt werden). Intern wird ein Iterator definiert, der mit Range<decltype(range)>::begin(range) initialisiert wird und mit jeden Schleifendurchlauf inkrementiert wird, bis er Range<decltype(range)>::end(range) erreicht. Das Element, auf das dieser Iterator zeigt, kann man dann jeweils über die Schleifenvariable element ansprechen. Das Range, über das for iteriert, sollte dabei nicht verändert werden.

Status - Oktober 2008
Die neue for-Schleife ist Teil des aktuellen Working-Drafts.

Unterstützung
Mir sind keine Compiler bekannt, die dieses Feature unterstützen.

Proposals
N2196 - Einführung und Formulierung
N2394 - Aktuelle Formulierung


2.5 Explizite Umwandlungsoperatoren

Um die implizite Konvertierung in einen selbstdefinierten Typ durch einen Konstruktor zu verhindern, wird in C++03 das Schlüsselwort explicit verwendet. In manchen Situationen ist es jedoch nötig, die Typumwandlung nicht von einem Konstruktor, sondern von einem speziellen Operator zur Typumwandlung durchführen zu lassen. Dies ist beispielsweise der Fall, wenn man keinen Zugriff auf die Implementierung der Zielklasse hat. Auch Smart-Pointer verwenden diese Möglichkeit, um beispielsweise einen operator bool zur Verfügung zu stellen. Smart-Pointer wie boost::shared_ptr geben in Wahrheit allerdings einen Typ zurück, der auch im Kontext von boolschen Werten verwendet werden kann, meistens einen Zeiger auf eine Elementvariable, denn würden sie einen boolschen Wert direkt zurückgeben, könnte dieser vom Compiler in Ausdrücken weiter umgewandelt - und letzten Endes falsch verwendet werden. Der std::shared_ptr wird daher einen explicit operator bool haben. Um den hässlichen Workaround mit Zeigern auf Elementvariablen zu umgehen, wird außerdem ein "bool-Kontext" eingeführt werden, in dem explizite Umwandlungsoperatoren nach bool automatisch aufgerufen werden. Dies geschieht im Kopf einer Schleife und in der Bedingung eines if-Statements.


Beispiel
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
template <class T>
struct ptr
{
   //…
   explicit operator bool () { return pointee; }
   T *pointee;
};

void foo (ptr x)
{
   //Automatische Konvertierung nach bool
   if (x);
     
   //Kein bool-Kontext, daher: Fehler
   if (x < 42);
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
template <class T>
struct ptr
{
//…
explicit operator bool () { return pointee; }
T *pointee;
};

void foo (ptr x)
{
//Automatische Konvertierung nach bool
if (x);

//Kein bool-Kontext, daher: Fehler
if (x < 42);
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
template <class T>
struct ptr
{
   //…
   explicit operator bool () { return pointee; }
   T *pointee;
};

void foo (ptr x)
{
   //Automatische Konvertierung nach bool
   if (x);
     
   //Kein bool-Kontext, daher: Fehler
   if (x < 42);
}


Status - Juni 2008
Dieses Feature ist Teil des Working-Drafts des kommenden C++-Standards.

Unterstützung
Mir sind keine Compiler bekannt, die dieses Feature unterstützen.

Proposals
N2437 - Explizite Umwandlungsoperatoren (Hintergründe)


2.6 Typsicheres enum

Aufzählungen (enums) in C++ haben alle möglichen Ecken und Kanten.

  • enums sind nicht vollständig typsicher. Es ist zwar nicht möglich, eine Zuweisung von einem enum-Typ zu einem anderen durchzuführen und es gibt auch keine implizite Konvertierung eines int-Wertes zu einem enum-Typ, aber enums können ganz leicht selbst zu int-Werten werden.
  • enums sind intern mit Hilfe eines Typs implementiert, der nicht explizit angegeben werden kann. Man kann daher nicht wissen, welche Größe eine enum-Variable einnehmen wird. Außerdem ist es nicht möglich, zu sagen, ob der zugrunde liegende Typ eines enums signed oder unsigned ist.
  • Die einzelnen Enumeratoren eines enums werden in den Namensbereich des enums selbst eingeführt.


Um diese Defizite zu umgehen, wird in C++09 eine neue Art enum eingeführt: die enum class.


Beispiel
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
1
2
3
4
5
6
7
8
9
10
11
12
13
14
enum class Color { Red, Green, Blue };
enum class Direction { Left, Down, Right, Up };

Color col = Direction::Left   //Fehler, auch mit einfachen enums

int i = Color::Red;           //Fehler, nur mit einfachen enums erlaubt

Direction dir = Left;         //Fehler, nur mit einfachen enums erlaubt

if (dir >= col)               //Schlimmer Fehler! Einfache enums würden dies allerdings zulassen.

enum class Size : uint32_t { Small, Medium, Big };
//Implementiert als 32-Bit unsigned Integer.
//(uint32_t aus dem Standard-Header <cstdint>)
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
enum class Color { Red, Green, Blue };
enum class Direction { Left, Down, Right, Up };

Color col = Direction::Left //Fehler, auch mit einfachen enums

int i = Color::Red; //Fehler, nur mit einfachen enums erlaubt

Direction dir = Left; //Fehler, nur mit einfachen enums erlaubt

if (dir >= col) //Schlimmer Fehler! Einfache enums würden dies allerdings zulassen.

enum class Size : uint32_t { Small, Medium, Big };
//Implementiert als 32-Bit unsigned Integer.
//(uint32_t aus dem Standard-Header <cstdint>)
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
enum class Color { Red, Green, Blue };
enum class Direction { Left, Down, Right, Up };

Color col = Direction::Left   //Fehler, auch mit einfachen enums

int i = Color::Red;           //Fehler, nur mit einfachen enums erlaubt

Direction dir = Left;         //Fehler, nur mit einfachen enums erlaubt

if (dir >= col)               //Schlimmer Fehler! Einfache enums würden dies allerdings zulassen.

enum class Size : uint32_t { Small, Medium, Big };
//Implementiert als 32-Bit unsigned Integer.
//(uint32_t aus dem Standard-Header <cstdint>)


Status - Juni 2008
Dieses Feature befindet sich bereits im Working-Draft des kommenden C++-Standards.

Unterstützung
Mir sind keine Compiler bekannt, die dieses Feature unterstützen.

Proposals
N2347 - Streng getypte enums (Hintegründe)


2.7 default-Funktionen

C++ bietet vier spezielle Elementfunktionen an: den Destruktor, den Standardkonstruktor, den Kopierkonstruktor und den Zuweisungsoperator. Diese Elementfunktionen werden vom Compiler automatisch erstellt, können jedoch jederzeit überschrieben werden.

Außerdem definiert C++ diverse globale Operatoren auch für selbstdefinierte Typen: operator , (der Sequenzoperator), operator & (der Adress-Operator), operator *, operator ->, operator ->*, operator new und operator delete.

Die Herangehensweise von C++03 hat jedoch einige Probleme: Deklariert man beispielsweise einen beliebigen, selbstdefinierten Konstruktor, wird kein Standardkonstruktor angelegt, implizite Destruktoren funktionieren nicht mit polymorphen Klassen, und selbstdefinierte Implementierungen sind nicht-trivial, verhindern also POD-Semantik.

Diese Probleme fallen besonders dann auf, wenn man versucht, zu verhindern, dass eine Klasse kopierbar ist: durch die Deklaration eines privaten Kopierkonstruktors und Zuweisungsoperators ohne Definition. Dadurch ist der Typ allerdings kein POD mehr und zusätzlich muss man einen eigenen Standardkonstruktor definieren.

In C++09 ist es nun möglich, explizit zu sagen, dass man für eine Klasse einen compilergenerierten Standardkonstruktor bekommen möchte - auch dass man einen bestimmten Konstruktor nicht haben will, ist einfach ausdrückbar.


Beispiel
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
struct Foo
{
   Foo() = default;           //Standardkonstruktor explizit verlangt
   virtual ~Foo () = default; //Implementierung dem Compiler überlassen
   Foo (Foo const&);
};

inline Foo::Foo (Foo const&) = default;

class Bar
{
public:
    Bar () = default;
   
    Bar& operator = (Bar const&) = delete;
    Bar (Bar const&) = delete;
    void* operator new (std::size_t) = delete;
};

void quux (long long);
void quux (long) = delete;
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
struct Foo
{
Foo() = default; //Standardkonstruktor explizit verlangt
virtual ~Foo () = default; //Implementierung dem Compiler überlassen
Foo (Foo const&);
};

inline Foo::Foo (Foo const&) = default;

class Bar
{
public:
Bar () = default;

Bar& operator = (Bar const&) = delete;
Bar (Bar const&) = delete;
void* operator new (std::size_t) = delete;
};

void quux (long long);
void quux (long) = delete;
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
struct Foo
{
   Foo() = default;           //Standardkonstruktor explizit verlangt
   virtual ~Foo () = default; //Implementierung dem Compiler überlassen
   Foo (Foo const&);
};

inline Foo::Foo (Foo const&) = default;

class Bar
{
public:
    Bar () = default;
   
    Bar& operator = (Bar const&) = delete;
    Bar (Bar const&) = delete;
    void* operator new (std::size_t) = delete;
};

void quux (long long);
void quux (long) = delete;


Erläuterung
Die Klasse Bar beschreibt einen Typ, der nicht kopierbar ist, da Kopierkonstruktor und Zuweisungsoperator gelöscht sind. Außerdem kann Bar nicht dynamisch mit new erzeugt werden, da auch operator new für Bar nicht existiert.

Auch freistehende Funktionen können gelöscht werden: Dies verbietet bei quux zum Beispiel eine Typumwandlung von long nach long long. Kurz gesagt: Eine Überladung für long wird zwar gefunden (die Version mit long long wird nicht verwendet), deren Definition ist aber gelöscht, was schon zur Compile-Zeit einen Fehler verursacht.

Status - Juni 2008
Dieses Feature ist bereits im Working-Draft des kommenden Standards enthalten.

Unterstützung
Mir sind keine Compiler bekannt, die dieses Feature unterstützen.

Proposals
N2346 - defaulted and deleted Functions (Hintegründe)


2.8 Plötzlich POD

POD ist die Abkürzung für plain-old-data und ist im C++-Standard von 2003 ziemlich streng definiert: Eine POD-Struktur ist eine Klasse, die nur PODs als Elementvariablen enthalten kann, die keinen selbstdefinierten Zuweisungsoperator, keine selbstdefinierten Konstruktoren und keinen selbstdefinierten Destruktor enthalten darf, die weiters keine privaten oder geschützten (protected) Elementvariablen aggregiert, keine Basisklassen hat und auch keine virtuellen Funktionen.

Es gibt demgegenüber jedoch einige Vorteile, für die es sich lohnt, PODs einzusetzen:

  • PODs sind byteweise kopierbar. Optimierungen mit std::memcpy sind dadurch möglich.
  • PODs sind mit Strukturen aus C layout-kompatibel.
  • Spezifische Initialisierungs-Garantien. Multithreaded Programme können data races während der Initialisierung von PODs umgehen.


Ein klassisches Beispiel, das die Absurdität dieser strengen Definition veranschaulicht:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
struct A
{
   int n;
};

struct B
{
   int n;
   B(int n_) : n(n_) {}
};
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
struct A
{
int n;
};

struct B
{
int n;
B(int n_) : n(n_) {}
};
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
struct A
{
   int n;
};

struct B
{
   int n;
   B(int n_) : n(n_) {}
};

In C++03 ist A eine POD-Struktur, B ist keine.

C++09 verändert die Definition von POD wie folgt:

  • PODs dürfen eigene Konstruktoren haben, solange der triviale Standardkonstruktor und die anderen speziellen Elementfunktionen verfügbar sind.
  • PODs dürfen Basisklassen haben, diese dürfen allerdings nicht polymorph sein. Eine der Basisklassen darf nicht-statische Elementvariablen enthalten, wenn die abgeleitete Klasse keine hat.
  • PODs haben Zugriffskontrolle. Allerdings müssen alle Elementvariablen denselben Zugriff erlauben.
  • PODs sind nun unabhängig von Aggregattypen definiert, deren eigentlicher Zweck es ist, eine spezielle Art von Initialisierung zur Verfügung zu stellen. PODs sind stattdessen nun in Form von trivialen Typen und Standard-Layout-Typen definiert. Triviale Klassen haben triviale spezielle Memberfunktionen (Standardkonstruktor, Kopierkonstruktor, Destruktor, Zuweisungsoperator), was virtuelle Funktionen und virtuelle Basisklassen ausschließt. Standard-Layout-Klassen haben nur Elementvariablen, die ebenfalls Standard-Layout-Klassen sind; sie haben weder virtuelle Funktionen noch virtuelle Basisklassen, dieselben Zugriffsrechte für alle Elementvariablen, besitzen nur Standard-Layout-Basisklassen, welche nur dann Elementvariablen beinhalten dürfen, wenn die von ihnen abgeleitete Klasse keine hat.

PODs sind dabei Standard-Layout-Typen und triviale Typen. Der Grund, diese neuen Definitionen einzuführen, liegt darin, dass man erkannt hat, dass an vielen Stellen im alten Standard der Begriff POD semantisch nicht korrekt war und sich entweder auf triviale Typen oder auf Standard-Layout-Typen bezog.

Durch die neue Definition werden einige Typen zu POD-Typen, die es davor nicht waren. Vor allem erlaubt es eine Änderung von std::pair, das danach eine POD-Struktur sein kann.

Status - Juni 2008
Dieses Feature ist bereits im Working-Draft des kommenden C++-Standards enthalten.

Unterstützung
Mir ist kein Compiler bekannt, der dieses Feature unterstützt.

Proposals
N2342 - PODs unstrung (Hintergründe)


2.9 nullptr

Der Wert 0 kann in C++ verschiedenes bedeuten. Einerseits ist er natürlich eine Ganzzahl mit dem Wert 0, andererseits kann 0 aber auch in einen Zeiger, den sogenannten Null-Zeiger umgewandelt werden. Dies schafft Probleme bei der Funktionsüberladung.
C/C++ Code:
1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
void f(int);
void f(char*);

f(0);                   //Ruft f(int) auf, niemals f(char*)


std::string s1(false);  //Kompiliert tadellos - ruft den char const*-Konstruktor mit dem Null-Zeiger auf
std::string s2(true);   //Fehler
C/C++ Code:
1
2
3
4
5
6
7
8
void f(int);
void f(char*);

f(0); //Ruft f(int) auf, niemals f(char*)


std::string s1(false); //Kompiliert tadellos - ruft den char const*-Konstruktor mit dem Null-Zeiger auf
std::string s2(true); //Fehler
C/C++ Code:
1
2
3
4
5
6
7
8
void f(int);
void f(char*);

f(0);                   //Ruft f(int) auf, niemals f(char*)


std::string s1(false);  //Kompiliert tadellos - ruft den char const*-Konstruktor mit dem Null-Zeiger auf
std::string s2(true);   //Fehler

Das Proposal, das nullptr vorschlägt (n2431) fasst dieses unintuitive Verhalten wie folgt zusammen:
A name for the null pointer: nullptr (revision 4), Proposal No. 2431 schrieb:

An alternative description of this effect might be: "0 is always both an integer constant and a null pointer constant, except when it's not."



Auch wenn C++09 aus Gründen der Code-Kompatibilität nicht auf die implizite Umwandlung von 0 in den Null-Zeiger verzichten will, wird ein neuer Null-Zeiger, genannt nullptr, eingeführt. nullptr hat dabei einen eigenen Typ, der über ein typedef in <cstddef> definiert ist:
C/C++ Code:
typedef decltype(nullptr) nullptr_t;
C/C++ Code:
typedef decltype(nullptr) nullptr_t;
C/C++ Code:
typedef decltype(nullptr) nullptr_t;

nullptr_t ist ein POD-Typ, konvertierbar in Zeiger-Typen und Zeiger-auf-Member-Typen. Ansonsten kann ein Objekt von diesem Typ in keinen anderen Typ umgewandelt werden, weder in integrale Typen noch in den bool-Typ.


Beispiel
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
char *a = nullptr;
char *b = 0;
int n = nullptr;        //Fehler

if (a == b);            //Bedingung erfüllt
if (a == 0);            //Bedingung erfüllt
if (n == nullptr);      //Fehler

char *c = expr ? nullptr : nullptr;  
char *d = expr ? 0 : nullptr;          //Fehler: Typen sind nicht kompatibel.

sizeof (nullptr);       //OK
typeid (nullptr);       //OK
throw nullptr;          //OK

void fun (char*);
void fun (int);

fun(nullptr);             //Ruft fun(char*) auf
fun(0);                   //Ruft fun(int) auf

template <typename T>
void bar (T t);

bar(0);        //decltype(t) == int
bar(nullptr);  //decltype(t) == nullptr_t
bar(static_cast<float*>(nullptr));  //decltype(t) == float*
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
char *a = nullptr;
char *b = 0;
int n = nullptr; //Fehler

if (a == b); //Bedingung erfüllt
if (a == 0); //Bedingung erfüllt
if (n == nullptr); //Fehler

char *c = expr ? nullptr : nullptr;
char *d = expr ? 0 : nullptr; //Fehler: Typen sind nicht kompatibel.

sizeof (nullptr); //OK
typeid (nullptr); //OK
throw nullptr; //OK

void fun (char*);
void fun (int);

fun(nullptr); //Ruft fun(char*) auf
fun(0); //Ruft fun(int) auf

template <typename T>
void bar (T t);

bar(0); //decltype(t) == int
bar(nullptr); //decltype(t) == nullptr_t
bar(static_cast<float*>(nullptr)); //decltype(t) == float*
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
char *a = nullptr;
char *b = 0;
int n = nullptr;        //Fehler

if (a == b);            //Bedingung erfüllt
if (a == 0);            //Bedingung erfüllt
if (n == nullptr);      //Fehler

char *c = expr ? nullptr : nullptr;  
char *d = expr ? 0 : nullptr;          //Fehler: Typen sind nicht kompatibel.

sizeof (nullptr);       //OK
typeid (nullptr);       //OK
throw nullptr;          //OK

void fun (char*);
void fun (int);

fun(nullptr);             //Ruft fun(char*) auf
fun(0);                   //Ruft fun(int) auf

template <typename T>
void bar (T t);

bar(0);        //decltype(t) == int
bar(nullptr);  //decltype(t) == nullptr_t
bar(static_cast<float*>(nullptr));  //decltype(t) == float*


Status - Juni 2008
Dieses Feature ist bereits im Working-Draft des aktuellen C++-Standards enthalten.

Unterstützung
Mir sind keine Compiler bekannt, die dieses Feature unterstützen.

Proposals
N2431 - nullptr (Hintergründe)


3 Ausblick

Im zweiten Teil dieser Serie möchte ich in ähnlicher Art und Weise wie hier einen Überblick über Neuerungen in der C++-Standardbibliothek geben. Die Standardbibliothek ist wohl der Teil des Standards, der sich am gröbsten erweitert hat: Von knapp unter 400 Seiten im Standard von 2003 zu über 700 Seiten im aktuellen Working-Draft, und dabei sind einige der neuen Libraries noch gar nicht mit dabei!


4 Quellen und Verweise

Direkte Quellen
Das C++-Standardisierungs Komitee
Der aktuelle Working-Draft
Alle Proposals nach Jahr
Offizieller Status der C++-Entwicklung
Die allerneuesten Proposals

Verweise
Quick'n'dirty - An Introduction to C++0x (November 2007)
A Brief Look at C++0x (Januar 2006)
B. Stroustrup: The Design of C++0x (C/C++ User's Journal, Mai 2005)
Stroustrup über Initialisierungslisten (youtube.com, Februar 2007)
C++-Sprachsupport in der GCC
Download von ConceptGCC

_________________
quadrathelm? quadratuaheln!
1, 4, 9, 16, 25, usw.


Zuletzt bearbeitet von queer_boy am 14:53:38 20.11.2008, insgesamt 15-mal bearbeitet
XP^
Mitglied

Benutzerprofil
Anmeldungsdatum: 10.06.2007
Beiträge: 152
Beitrag XP^ Mitglied 13:49:52 13.02.2008   Titel:   Guter Überblick :)            Zitieren

Ist ein ziemlich guter Artikel :live:

Allerdings entäuscht mich das neue c++09 ein bisschen wegen der neuen Syntax in einigen Fällen :(

Ansonsten ist das mit zb nullpointern ziemlich nützlich würd ich mal sagen.

_________________
Dual Core Do more,
Quad Core wait more!
Ribosom
Mitglied

Benutzerprofil
Anmeldungsdatum: 29.01.2008
Beiträge: 32
Beitrag Ribosom Mitglied 14:06:14 13.02.2008   Titel:              Zitieren

Wie siehts mit der Compilerunterstützung durch Microsoft aus?


Zuletzt bearbeitet von Ribosom am 14:09:19 13.02.2008, insgesamt 1-mal bearbeitet
XP^
Mitglied

Benutzerprofil
Anmeldungsdatum: 10.06.2007
Beiträge: 152
Beitrag XP^ Mitglied 14:18:39 13.02.2008   Titel:              Zitieren

Ribosom schrieb:
Wie siehts mit der Compilerunterstützung durch Microsoft aus?


Anscheinend wirds erst mit der nächsten MSVC Version untersützt.

_________________
Dual Core Do more,
Quad Core wait more!
Artchi
Autor

Benutzerprofil
Anmeldungsdatum: 16.03.2002
Beiträge: 8576
Beitrag Artchi Autor 14:34:53 13.02.2008   Titel:              Zitieren

Wieso "erst"? :rolleyes: Wenns noch keinen Standard gibt, brauchts auch kein Support dafür geben. Was nicht heißen muß, das intern schon die ersten Implementierungen gemacht werden.

Zitat:
Right Angle Brackets. >> wird im Kontext von Templates nicht mehr als Right-Shift-Operator interpretiert.

Wird schon seit MSVC2005 unterstützt.

_________________
Bring back the Windows Start Menu Petition | GoPetition
Optimizer
Mitglied

Benutzerprofil
Anmeldungsdatum: 19.09.2002
Beiträge: 8317
Beitrag Optimizer Mitglied 15:40:30 13.02.2008   Titel:              Zitieren

concepts sind :live: . Schade dass es weiterhin eine implizite Umwandlung von 0 nach nullptr geben wird. Ich bin sicher, dass man bestehenden Quellcode mit automatisierten Tools anpassen könnte. Danke für den informativen Artikel.

_________________
Nichts zu verbergen™ - dein Beitrag zum Krieg gegen den Terrorismus!
Badestrand
Mitglied

Benutzerprofil
Anmeldungsdatum: 29.08.2006
Beiträge: 4342
Beitrag Badestrand Mitglied 15:58:48 13.02.2008   Titel:              Zitieren

Gut erklärt! Eine Frage hätte ich aber noch:
queer_boy schrieb:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
#include <iterator_concept>

template <class T>
void test (T range)
{
   for (auto& element: range)
   {                          
      element *= 2;
   }
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
#include <iterator_concept>

template <class T>
void test (T range)
{
for (auto& element: range)
{
element *= 2;
}
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
#include <iterator_concept>

template <class T>
void test (T range)
{
   for (auto& element: range)
   {                          
      element *= 2;
   }
}

Wie würde ich das aufrufen?


Zuletzt bearbeitet von Badestrand am 15:59:09 13.02.2008, insgesamt 1-mal bearbeitet
queer_boy
Mitglied

Benutzerprofil
Anmeldungsdatum: 02.11.2006
Beiträge: 1035
Beitrag queer_boy Mitglied 16:03:53 13.02.2008   Titel:              Zitieren

Badestrand schrieb:
Gut erklärt! Eine Frage hätte ich aber noch:
queer_boy schrieb:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
#include <iterator_concept>

template <class T>
void test (T range)
{
   for (auto& element: range)
   {                          
      element *= 2;
   }
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
#include <iterator_concept>

template <class T>
void test (T range)
{
for (auto& element: range)
{
element *= 2;
}
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
#include <iterator_concept>

template <class T>
void test (T range)
{
   for (auto& element: range)
   {                          
      element *= 2;
   }
}

Wie würde ich das aufrufen?


zb. mit
C/C++ Code:
1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
int main ()
{
   vector<int> v { 1, 2, 3, 4, 5 };
   test (v);
   //oder
   int arr[] = { 6, 7, 8 };
   test (arr);
}
C/C++ Code:
1
2
3
4
5
6
7
8
int main ()
{
vector<int> v { 1, 2, 3, 4, 5 };
test (v);
//oder
int arr[] = { 6, 7, 8 };
test (arr);
}
C/C++ Code:
1
2
3
4
5
6
7
8
int main ()
{
   vector<int> v { 1, 2, 3, 4, 5 };
   test (v);
   //oder
   int arr[] = { 6, 7, 8 };
   test (arr);
}


die funktion würde man wohl auch eher als
C/C++ Code:
template <typename T>
requires Range<T>
void test (T& range)
//oder
template <Range R>
void test (R& range)
C/C++ Code:
template <typename T>
requires Range<T>
void test (T& range)
//oder
template <Range R>
void test (R& range)
C/C++ Code:
template <typename T>
requires Range<T>
void test (T& range)
//oder
template <Range R>
void test (R& range)

deklarieren. aber das hab ich in dem beispiel aus gründen der übersichtlichkeit weggelassen.

_________________
quadrathelm? quadratuaheln!
1, 4, 9, 16, 25, usw.


Zuletzt bearbeitet von queer_boy am 16:04:27 13.02.2008, insgesamt 1-mal bearbeitet
rüdiger
Moderator

Benutzerprofil
Anmeldungsdatum: 11.07.2001
Beiträge: 22819
Beitrag rüdiger Moderator 16:25:16 13.02.2008   Titel:              Zitieren

:live: gute Arbeit! Ich freue mich schon auf C++09 :)

@Ribosom
Hat der MSVC überhaupt schon eine TR1-Implementierung?

_________________
.
Artchi
Autor

Benutzerprofil
Anmeldungsdatum: 16.03.2002
Beiträge: 8576
Beitrag Artchi Autor 17:35:14 13.02.2008   Titel:              Zitieren

rüdiger! Es gibt mittlerweile ein sogenanntes Feature-Pack für MSVS2008 von MS als Beta, in dem auch ein TR1 drin ist. Das Final soll noch in diesem Quartal raus kommen.

_________________
Bring back the Windows Start Menu Petition | GoPetition


Zuletzt bearbeitet von Artchi am 17:37:08 13.02.2008, insgesamt 1-mal bearbeitet
Enttäuschter
Unregistrierter




Beitrag Enttäuschter Unregistrierter 18:08:07 13.02.2008   Titel:              Zitieren

Juhu, C++ wird also noch komplexer. :rolleyes:
mikey
Mitglied

Benutzerprofil
Anmeldungsdatum: 26.05.2006
Beiträge: 1724
Beitrag mikey Mitglied 18:10:09 13.02.2008   Titel:              Zitieren

[ ]Du hast Ahnung von C++.
Aufjedenfall danke für den informativen Artikel! :)


Zuletzt bearbeitet von mikey am 18:11:15 13.02.2008, insgesamt 1-mal bearbeitet
Walli
Mitglied

Benutzerprofil
Anmeldungsdatum: 15.09.2002
Beiträge: 10941
Beitrag Walli Mitglied 18:39:56 13.02.2008   Titel:              Zitieren

Na toll, dann ist also nächstes Jahr ein wenig Lernerei angesagt um C++-technisch nicht "old school" zu programmieren. Die Artikel werde ich mir zu gegebener Zeit mal als gute Zusammenfassung reinziehen. Danke dafür :) .
darthdespotism
Autor

Benutzerprofil
Anmeldungsdatum: 23.02.2007
Beiträge: 1441
Beitrag darthdespotism Autor 18:47:14 13.02.2008   Titel:              Zitieren

Artchi schrieb:
rüdiger! Es gibt mittlerweile ein sogenanntes Feature-Pack für MSVS2008 von MS als Beta, in dem auch ein TR1 drin ist. Das Final soll noch in diesem Quartal raus kommen.


Teilweise enthalten ;) wenn ich das richtig im Kopf habe

_________________
There are only 10 types of people in the world: Those who understand binary, and those who don't.
http://christoph.devler.coders-nemesis.eu
enttäuscht
Unregistrierter




Beitrag enttäuscht Unregistrierter 21:10:24 13.02.2008   Titel:              Zitieren

struct schaut so aus...

C/C++ Code:
struct enttaeuscht
{
int a: 4;
//..
} // ohne ;   echt blöder Stil
C/C++ Code:
struct enttaeuscht
{
int a: 4;
//..
} // ohne ; echt blöder Stil
C/C++ Code:
struct enttaeuscht
{
int a: 4;
//..
} // ohne ;   echt blöder Stil
Optimizer
Mitglied

Benutzerprofil
Anmeldungsdatum: 19.09.2002
Beiträge: 8317
Beitrag Optimizer Mitglied 22:41:53 13.02.2008   Titel:              Zitieren

Das fehlende Semikolon ist doch logisch. Bei Funktionen machst du sowas auch nicht hin.

_________________
Nichts zu verbergen™ - dein Beitrag zum Krieg gegen den Terrorismus!
convenience-freak
Unregistrierter




Beitrag convenience-freak Unregistrierter 22:48:55 13.02.2008   Titel:              Zitieren

Enttäuschter schrieb:
Juhu, C++ wird also noch komplexer. :rolleyes:

ich find's auch völlig unverständlich, wie man die komplexeste programmiersprache der welt noch weiter aufmotzen kann. ist halt nur noch was für super-nerds.

--> C++ shows all signs of following the Harley Davidson Design Methodology - "If it breaks, make it bigger. If it sticks out, chrome it."
:)
enttäuscht
Unregistrierter




Beitrag enttäuscht Unregistrierter 23:23:08 13.02.2008   Titel:              Zitieren

Optimizer schrieb:
Das fehlende Semikolon ist doch logisch.


eben nicht.

im aktuellen c++ standard macht man ein ";" hin.
Blue-Tiger
Mitglied

Benutzerprofil
Anmeldungsdatum: 29.11.2002
Beiträge: 2979
Beitrag Blue-Tiger Mitglied 01:45:46 14.02.2008   Titel:              Zitieren

Hmmm... mir war gar nicht klar dass es so viel neue Syntax geben wuerde, irgendwie bin ich nicht so begeistert davon. Die Features verstaerken zwar die Ausdrucksstaerke, aber verlangen noch mehr Einarbeitungszeit fuer einen Frischling...

Jedenfalls danke fuer den Artikel :)NRVO

_________________
I have come here to chew memory and kick ass... and malloc() is returning a null pointer.
This message has been ROT-13 encrypted twice for higher security.
http://bluetiger.bauchlandung.org/
wurschtel-freak
Unregistrierter




Beitrag wurschtel-freak Unregistrierter 09:04:32 14.02.2008   Titel:              Zitieren

Blue-Tiger schrieb:
Hmmm... mir war gar nicht klar dass es so viel neue Syntax geben wuerde, irgendwie bin ich nicht so begeistert davon. Die Features verstaerken zwar die Ausdrucksstaerke, aber verlangen noch mehr Einarbeitungszeit fuer einen Frischling...

naja, der frischling wird wohl eher locker an die sache rangehen und muss nicht alles in kurzer zeit lernen. wirklich probleme werden wohl eher die leute kriegen, die sich etwas mehr zutrauen aber noch nicht absolut sattelfest sind. gerade von solchen, die c++ beruflich nutzen müssen, wird wohl so mancher wutausbruch zu erwarten sein. mir isses egal, soll sich c++ ruhig sein eigenes grab schaufeln.
:)
Artchi
Autor

Benutzerprofil
Anmeldungsdatum: 16.03.2002
Beiträge: 8576
Beitrag Artchi Autor 10:53:16 14.02.2008   Titel:              Zitieren

Viele Sprachfeatures (vorallem die Variadic-Templates, Concepts) werden eher für Library-Entwickler interessant sein. Und das sind eigentlich auch die (meiner Meinung nach) komplexeren neueren Features. Viele C++-Einsteiger werden eher Anwendungen entwickeln und nicht eine Library. D.h. sie werden sich mit den komplexeren Themen garnicht auseinander setzen müssen. Das ist ja auch heute schon so mit den Templates. Als Anfänger benutzt man doch eher fertige Templates aus der Std-Library und das ist doch recht einfach, oder? Und hier machen die Concepts es sogar noch einfacher für einen Template-Anwender, weil er bei einer Falschbenutzung verständlichere Fehlermeldungen erhält.

Irgendwann wird der nächste Step für einen Template-Anwender sein, das er vielleicht selber Templates und somit Libraries entwickelt. Dann wird er natürlich auf die vielen Features stossen. Gut, er wird natürlich viel lernen müssen. Aber auch nicht alles auf einmal. Es ist ja immer ein Lernprozess dahinter.

Übrigens, ich sehe es eigentlich nüchtern: andere Sprachen haben weniger Sprachfeatures ggü. C++, aber sie gleichen das mit viel Tools und Frameworks wieder aus. Und diese muß man ja auch lernen. Wir benutzen hier auf Arbeit die OSGi und Eclipse Platform, da wird das Classloading u.ä. total anders gehandhabt, als in der Standard-Java-Runtime. Es ist also eine Erweiterung an der Basis, wenn auch nicht an der Sprache. Jemand der Java kann, muß diese Erweiterung von OSGi und Eclipse ebenfalls zusätzlich lernen, um in unseren Projekten mitarbeiten zu können. Aber lernen muß man immer. Im C++09 wirds halt die Features in der Sprache geben.

_________________
Bring back the Windows Start Menu Petition | GoPetition


Zuletzt bearbeitet von Artchi am 11:00:13 14.02.2008, insgesamt 3-mal bearbeitet
sprachen-freak
Unregistrierter




Beitrag sprachen-freak Unregistrierter 11:12:39 14.02.2008   Titel:              Zitieren

Artchi schrieb:

Gut, er wird natürlich viel lernen müssen. Aber auch nicht alles auf einmal.

so wie ein chinese seine ca. 90000 schriftzeichen. :D
:)
otze
Mitglied

Benutzerprofil
Anmeldungsdatum: 15.01.2004
Beiträge: 6655
Beitrag otze Mitglied 11:19:19 14.02.2008   Titel:              Zitieren

Und C++ wird nicht komplexer. die neuen features sind allesamt Lösungen für Hacks die in der vergangenheit verwendet wurden.
Variadic templates sind endlich eine Lösung für probleme die bislang mit Preprocessor librarys gelöst werden mussten. Halt der Klassische Fall: eine funktion für 0-n argumente. Und der hack ist wesentlich komplizierter als Variadic templates.

_________________
Jesus Christus! Da blickt ja kein Mensch mehr durch.
hacking-freak.
Unregistrierter




Beitrag hacking-freak. Unregistrierter 11:26:03 14.02.2008   Titel:              Zitieren

otze schrieb:

die neuen features sind allesamt Lösungen für Hacks die in der vergangenheit verwendet wurden.

aber die alten hacks bleiben allesamt erhalten, oder?
:)
Artchi
Autor

Benutzerprofil
Anmeldungsdatum: 16.03.2002
Beiträge: 8576
Beitrag Artchi Autor 11:41:07 14.02.2008   Titel:              Zitieren

Nö, die kannst du ja jetzt durch die neuen Sprachfeatures ersetzen.

_________________
Bring back the Windows Start Menu Petition | GoPetition
Phoemuex
Moderator

Benutzerprofil
Anmeldungsdatum: 06.10.2004
Beiträge: 554
Beitrag Phoemuex Moderator 23:00:45 15.02.2008   Titel:              Zitieren

Vielen Dank für den Artikel, ich habe noch eine Frage: Wieso hast du nichts zu dem Garbage-Collector geschrieben, der ja wenigstens geplant war? Wird der im endgültigen Standard doch nicht enthalten sein (hoffentlich :D) oder hat das andere Gründe?

Felix

_________________
Everything is possible. The impossible just takes longer.
Ben04
Autor

Benutzerprofil
Anmeldungsdatum: 10.10.2004
Beiträge: 1635
Beitrag Ben04 Autor 23:05:25 15.02.2008   Titel:              Zitieren

In C++09 wird der soweit ich weiß nicht drin sein.
Optimizer
Mitglied

Benutzerprofil
Anmeldungsdatum: 19.09.2002
Beiträge: 8317
Beitrag Optimizer Mitglied 23:13:45 15.02.2008   Titel:              Zitieren

Weiß jemand, welche Art GC für C++ angedacht ist? Sollte es dann wie in C++/CLI dafür eigene Pointer-Typen geben, oder würde es sowas wie der Boehm Collector (= konservativ) werden? Sorry, falls es zu offtopic wird, ich frage dann auch nicht mehr genauer nach. Mich interessiert das Thema GC nur generell.

Btw. sehe ich grad noch die verbesserten for-loops. Ich bin froh, dass es das jetzt auf Sprachebene geben wird. Das mit den Makros ist einfach nichts gescheites.

_________________
Nichts zu verbergen™ - dein Beitrag zum Krieg gegen den Terrorismus!
queer_boy
Mitglied

Benutzerprofil
Anmeldungsdatum: 02.11.2006
Beiträge: 1035
Beitrag queer_boy Mitglied 00:03:13 16.02.2008   Titel:              Zitieren

Der GC ist vom Komitee zurückgestuft worden, weil da einfach noch zu viel unklar ist. Nix mit 09 also.
Das Komitee schreibt dazu:
Zitat:

A second proposed compromise to meet the timetable is the scaling back of the garbage collection feature. It is planned to remove known problems that inhibit garbage collected implementations, without actively designing a new feature.


d.h., das ist alles, was in C++09 drin sein wird.

Ein GC also entweder in einem späteren Standard oder als Technical Report.


Optimizer schrieb:
Weiß jemand, welche Art GC für C++ angedacht ist? Sollte es dann wie in C++/CLI dafür eigene Pointer-Typen geben, oder würde es sowas wie der Boehm Collector (= konservativ) werden? Sorry, falls es zu offtopic wird, ich frage dann auch nicht mehr genauer nach. Mich interessiert das Thema GC nur generell.

C++/CLI wird im letzten (zurückgestuften) Proposal *nicht* empfohlen. Es ist angedacht, Programme voll unter die Kontrolle eines GCs zu stellen (wobei das optional (bzw. "programmer-directed") aktiviert werden soll, wo auch z.B. ints nach Adressen auf Objekte untersucht werden sollen (zumindest, wenn man sie als gc_relaxed deklariert).
Aber H. Boehm kann das in seinem Proposal sicher besser als ich zusammenfassen.

AFAIR geht die Syntax für ein new ohne GC dann so:
C/C++ Code:
new (nogc) X;
//und
malloc_nogc
C/C++ Code:
new (nogc) X;
//und
malloc_nogc
C/C++ Code:
new (nogc) X;
//und
malloc_nogc


Es wird dann auch möglich sein, das ganze auf der Ebene von Übersetzungseinheiten zu steuern. Mit einem
C/C++ Code:
gc_forbidden;
C/C++ Code:
gc_forbidden;
C/C++ Code:
gc_forbidden;

wird der GC abgeschaltet (für die eine Unit), auch ein Objekt gc_lock lock; kann per RAII für eine einzelne Funktion den GC unterbinden.

Ich habe das aber weder hier noch im nächsten Artikel angesprochen, weil es eben nicht Teil von 09 sein wird.

Achja: Der GC wird *keine* Destruktoren aufrufen, auch kein finally ist angedacht.

_________________
quadrathelm? quadratuaheln!
1, 4, 9, 16, 25, usw.


Zuletzt bearbeitet von queer_boy am 00:04:33 16.02.2008, insgesamt 1-mal bearbeitet
Optimizer
Mitglied

Benutzerprofil
Anmeldungsdatum: 19.09.2002
Beiträge: 8317
Beitrag Optimizer Mitglied 01:10:09 16.02.2008   Titel:              Zitieren

Danke. :)

_________________
Nichts zu verbergen™ - dein Beitrag zum Krieg gegen den Terrorismus!
C++-Prokkramierer
Unregistrierter




Beitrag C++-Prokkramierer Unregistrierter 17:13:11 16.02.2008   Titel:              Zitieren

Wozu auch nen GC? Jeder C++ Programmierer ist es doch gewohnt ohne zu Leben und weiß damit umzugehen (smart-ptr), von daher sehe ich da keinen Vorteil den in den Standard aufzunehmen und GC-Bibliotheken gibt es ja bereits für die die es dennoch brauchen.

Mir gefallen die Ideen der neuen Konzepte sehr gut, aber deren Syntax gefällt mir zum Großteil weniger :/
Ben04
Autor

Benutzerprofil
Anmeldungsdatum: 10.10.2004
Beiträge: 1635
Beitrag Ben04 Autor 18:21:01 16.02.2008   Titel:              Zitieren

Wenn jemand gerne über das Thema "GC in C++XY" dann soll er bitte ein Topic in RudP eröffnen.
KasF
Mitglied

Benutzerprofil
Anmeldungsdatum: 14.12.2004
Beiträge: 2378
Beitrag KasF Mitglied 14:11:38 17.02.2008   Titel:              Zitieren

Schöner Artikel :) :live:

Ne Frage: Wieso kann man decltype nicht erweitern, um es folgendermaßen benutzen zu können:
C/C++ Code:
decltype(int + double); // Kann das ein Ausruck sein ? Müsste man den Standard bissl umschreiben ;)
C/C++ Code:
decltype(int + double); // Kann das ein Ausruck sein ? Müsste man den Standard bissl umschreiben ;)
C/C++ Code:
decltype(int + double); // Kann das ein Ausruck sein ? Müsste man den Standard bissl umschreiben ;)


Das müsste sich doch leicht machen lassen, dann würde man auch Funktionen leicher deklarieren können:
C/C++ Code:
template<class A, class B>
decltype(A + B) operator+( const A& a, const B& b);
C/C++ Code:
template<class A, class B>
decltype(A + B) operator+( const A& a, const B& b);
C/C++ Code:
template<class A, class B>
decltype(A + B) operator+( const A& a, const B& b);


Und wenn nicht könnte man sich die "komplizierte" Funktionsdeklaration sparen, indem man decltype in Kombination mit T() benutzt, dann hätte man wieder seinen normalen Ausdruck:
C/C++ Code:
template<class A, class B>
decltype(A() + B()) operator+( const A& a, const B& b);
C/C++ Code:
template<class A, class B>
decltype(A() + B()) operator+( const A& a, const B& b);
C/C++ Code:
template<class A, class B>
decltype(A() + B()) operator+( const A& a, const B& b);

Alle Build'ins haben (), natürlich müsste T dieses dann auch bereitstellen ...

_________________
Um C++ zu beherrschen muss man schon for( ;; ) fragen ob er genug Zeit für einen hat ...


Zuletzt bearbeitet von KasF am 14:17:26 17.02.2008, insgesamt 2-mal bearbeitet
KasF
Mitglied

Benutzerprofil
Anmeldungsdatum: 14.12.2004
Beiträge: 2378
Beitrag KasF Mitglied 14:21:08 17.02.2008   Titel:              Zitieren

... Ist decltype überhaupt nen Compile-Zeit-Operator ?

_________________
Um C++ zu beherrschen muss man schon for( ;; ) fragen ob er genug Zeit für einen hat ...
Prokkramierer
Unregistrierter




Beitrag Prokkramierer Unregistrierter 17:36:42 17.02.2008   Titel:              Zitieren

KasF schrieb:
... Ist decltype überhaupt nen Compile-Zeit-Operator ?

Muss es, da C++ ein statisches Typsystem hat.
KasF
Mitglied

Benutzerprofil
Anmeldungsdatum: 14.12.2004
Beiträge: 2378
Beitrag KasF Mitglied 21:54:36 18.02.2008   Titel:              Zitieren

Prokkramierer schrieb:
Muss es, da C++ ein statisches Typsystem hat.
Stimmt ja :)

Was ist mit dem Trick nun:
C/C++ Code:
template<class A, class B>
decltype(A() + B()) operator+( const A& a, const B& b);
C/C++ Code:
template<class A, class B>
decltype(A() + B()) operator+( const A& a, const B& b);
C/C++ Code:
template<class A, class B>
decltype(A() + B()) operator+( const A& a, const B& b);

anstatt:
C/C++ Code:
template<class A, class B>
auto operator+( const A& a, const B& b) -> decltype(a + b);
C/C++ Code:
template<class A, class B>
auto operator+( const A& a, const B& b) -> decltype(a + b);
C/C++ Code:
template<class A, class B>
auto operator+( const A& a, const B& b) -> decltype(a + b);


Kann das funktionieren ?

_________________
Um C++ zu beherrschen muss man schon for( ;; ) fragen ob er genug Zeit für einen hat ...
Bashar
Mitglied

Benutzerprofil
Anmeldungsdatum: 15.05.2001
Beiträge: 16812
Beitrag Bashar Mitglied 22:21:25 18.02.2008   Titel:              Zitieren

KasF schrieb:

Was ist mit dem Trick nun:
C/C++ Code:
template<class A, class B>
decltype(A() + B()) operator+( const A& a, const B& b);
C/C++ Code:
template<class A, class B>
decltype(A() + B()) operator+( const A& a, const B& b);
C/C++ Code:
template<class A, class B>
decltype(A() + B()) operator+( const A& a, const B& b);


Ich würde mal aus dem Bauch heraus sagen, das funktioniert ohne Probleme, wenn A und B default-konstruierbar sind.

_________________
OSL♥
camper
Mitglied

Benutzerprofil
Anmeldungsdatum: 06.08.2004
Beiträge: 5054
Beitrag camper Mitglied 23:48:20 18.02.2008   Titel:              Zitieren

KasF schrieb:
[Was ist mit dem Trick nun:
C/C++ Code:
template<class A, class B>
decltype(A() + B()) operator+( const A& a, const B& b);
C/C++ Code:
template<class A, class B>
decltype(A() + B()) operator+( const A& a, const B& b);
C/C++ Code:
template<class A, class B>
decltype(A() + B()) operator+( const A& a, const B& b);
Kann das funktionieren ?
Daran ist nichts auszusetzen - aber ist das wirklich einfacher?
Die andere Deklarationsform erlaubt es, den typbestimmenden Ausdruck genauso zu schreiben, wie er dann tatsächlich in der Implementation vorkommt - bei traditioneller Schreibweise wie hier sieht das dagegen doch recht umständlich aus (insbesondere wenn die Funktionsparametertypen komplexer werden (häufig genug werden die ja irgendwie komplex aus den Templateparametern zusammengesetzt).
Was ich evtl. kritisieren würde, ist, dass auch bei neuer Schreibweise immer noch Codeduplizität auftritt - der decltype-Ausdruck nimmt ja im Grunde die Implementation vorweg. So gesehen wäre es ggf. wünschenswert, den return-Typ gar nicht explizit angeben zu müssen und auf diesen aus der Implementation zu schließen, z.B.:
C/C++ Code:
template<typename T, typename U>
constexpr auto max(T&& a, U&& b) { return a < b ? b : a; } // implizit inline auch ohne constexpr, statt
template<typename T, typename U>
constexpr auto max(T&& a, U&& b) -> decltype( a < b ? b : a ) { return a < b ? b : a; }
C/C++ Code:
template<typename T, typename U>
constexpr auto max(T&& a, U&& b) { return a < b ? b : a; } // implizit inline auch ohne constexpr, statt
template<typename T, typename U>
constexpr auto max(T&& a, U&& b) -> decltype( a < b ? b : a ) { return a < b ? b : a; }
C/C++ Code:
template<typename T, typename U>
constexpr auto max(T&& a, U&& b) { return a < b ? b : a; } // implizit inline auch ohne constexpr, statt
template<typename T, typename U>
constexpr auto max(T&& a, U&& b) -> decltype( a < b ? b : a ) { return a < b ? b : a; }
Das wäre denkbar, wenn die Implementation wie bei contexpr dann vornherein auf ein einzelnes return-Statement beschränkt ist (die meisten Fälle, die mir einfallen, sollten sowieso constexpr sein). Ist aber wahrscheinlich nicht wichtig genug, um die Sprache dafür zu ändern.


Zuletzt bearbeitet von camper am 23:49:08 18.02.2008, insgesamt 1-mal bearbeitet
queer_boy
Mitglied

Benutzerprofil
Anmeldungsdatum: 02.11.2006
Beiträge: 1035
Beitrag queer_boy Mitglied 05:33:28 19.02.2008   Titel:              Zitieren

Bashar schrieb:
KasF schrieb:

Was ist mit dem Trick nun:
C/C++ Code:
template<class A, class B>
decltype(A() + B()) operator+( const A& a, const B& b);
C/C++ Code:
template<class A, class B>
decltype(A() + B()) operator+( const A& a, const B& b);
C/C++ Code:
template<class A, class B>
decltype(A() + B()) operator+( const A& a, const B& b);


Ich würde mal aus dem Bauch heraus sagen, das funktioniert ohne Probleme, wenn A und B default-konstruierbar sind.

oder man würde auf nummer sicher gehen:
C/C++ Code:
template <class A, class B>
decltype(*static_cast<A*>(0) + *static_cast<B*>(0)) operator + (A const&, B const&);
C/C++ Code:
template <class A, class B>
decltype(*static_cast<A*>(0) + *static_cast<B*>(0)) operator + (A const&, B const&);
C/C++ Code:
template <class A, class B>
decltype(*static_cast<A*>(0) + *static_cast<B*>(0)) operator + (A const&, B const&);

das ist umständlich.

camper schrieb:

Was ich evtl. kritisieren würde, ist, dass auch bei neuer Schreibweise immer noch Codeduplizität auftritt - der decltype-Ausdruck nimmt ja im Grunde die Implementation vorweg. So gesehen wäre es ggf. wünschenswert, den return-Typ gar nicht explizit angeben zu müssen und auf diesen aus der Implementation zu schließen, z.B.:
C/C++ Code:
template<typename T, typename U>
constexpr auto max(T&& a, U&& b) { return a < b ? b : a; } // implizit inline auch ohne constexpr, statt
template<typename T, typename U>
constexpr auto max(T&& a, U&& b) -> decltype( a < b ? b : a ) { return a < b ? b : a; }
C/C++ Code:
template<typename T, typename U>
constexpr auto max(T&& a, U&& b) { return a < b ? b : a; } // implizit inline auch ohne constexpr, statt
template<typename T, typename U>
constexpr auto max(T&& a, U&& b) -> decltype( a < b ? b : a ) { return a < b ? b : a; }
C/C++ Code:
template<typename T, typename U>
constexpr auto max(T&& a, U&& b) { return a < b ? b : a; } // implizit inline auch ohne constexpr, statt
template<typename T, typename U>
constexpr auto max(T&& a, U&& b) -> decltype( a < b ? b : a ) { return a < b ? b : a; }


ich habe dunkel in erinnerung, diesen vorschlag irgendwo gelesen zu haben. ein schnelles durchschauen der passenden dokumente hat aber jetzt irgendwie nichts gebracht. ich wüsste jetzt aber nicht einmal mehr, wie weit ausgereift dieser vorschlag wäre.

_________________
quadrathelm? quadratuaheln!
1, 4, 9, 16, 25, usw.
KasF
Mitglied

Benutzerprofil
Anmeldungsdatum: 14.12.2004
Beiträge: 2378
Beitrag KasF Mitglied 14:28:21 19.02.2008   Titel:              Zitieren

camper schrieb:
aber ist das wirklich einfacher?

Kommt wahrscheinlich auf die Funktion an. Bei op+ zb sind mir ja die Parameter egal, mich interessiert ja nur der Typ. Hingegen bei deinem max müsste ich die auto -> decltype Variante benutzen.

Wobei ich auto -> decltype irgendwie schöner finde, also decltype( T()+U() ) :)

camper schrieb:

Was ich evtl. kritisieren würde, ist, dass auch bei neuer Schreibweise immer noch Codeduplizität auftritt - der decltype-Ausdruck nimmt ja im Grunde die Implementation vorweg.

Hmmm, das gefällt mir irgendwie gar nicht, wäre schön wenn das so Umgesetzt werden könnte, wie du es vorgeschlagen hast.

_________________
Um C++ zu beherrschen muss man schon for( ;; ) fragen ob er genug Zeit für einen hat ...
Frickler
Unregistrierter




Beitrag Frickler Unregistrierter 17:02:20 19.02.2008   Titel:              Zitieren

Lol wie geil jetzt werden Kritiken an der neuen Syntax schon gelöscht :live:
GPC
Moderator

Benutzerprofil
Anmeldungsdatum: 11.07.2004
Beiträge: 6298
Beitrag GPC Moderator 20:34:30 19.02.2008   Titel:              Zitieren

Frickler schrieb:
Lol wie geil jetzt werden Kritiken an der neuen Syntax schon gelöscht :live:

Nein, ich lösche Posts die offensichtlich nur einen Flamewar provozieren.
Frickler
Unregistrierter




Beitrag Frickler Unregistrierter 23:52:33 19.02.2008   Titel:              Zitieren

Ich habe doch nur meine subjektive Meinung dazu abgegeben. Gut der letzte Satz konnte auch falsch verstanden werden, aber einen Flamewar wollte ich damit nicht provozieren, sondern nur darauf hinweisen, dass es in anderen Sprachen doch auch mit etwas weniger kryptischer Syntax geht.
Ben04
Autor

Benutzerprofil
Anmeldungsdatum: 10.10.2004
Beiträge: 1635
Beitrag Ben04 Autor 00:33:16 20.02.2008   Titel:              Zitieren

Langsamer wird das aber wirklich sehr stark OT hier. Hier gehören Beiträge zum und Diskussionen über den Artikel hin, nicht wie man C++09 besser machen könnte und schon gar keine Diskussion über einen Flamewar. Dafür sind NDR und RudP da,
GPC
Moderator

Benutzerprofil
Anmeldungsdatum: 11.07.2004
Beiträge: 6298
Beitrag GPC Moderator 15:22:06 10.03.2008   Titel:              Zitieren

Diskussionen die nicht direkt zum Artikel gehören ab jetzt hier: http://c-plusplus.de/forum/viewtopic-var-t-is-207658.html
queer_boy
Mitglied

Benutzerprofil
Anmeldungsdatum: 02.11.2006
Beiträge: 1035
Beitrag queer_boy Mitglied 20:50:16 31.05.2008   Titel:              Zitieren

so, ich habe nun nach neuerlichem durchforsten von http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2597.html den status der jeweiligen features neu beurteilt. einige veränderungen kurz: closures (mit einer leicht unterschiedlichen syntax als die, die ich ursprünglich im artikel hatte - schon nachgebessert), die neue funktionsdeklaration und ein paar kleinere sachen sind im working draft; noch nicht dabei: die neue for-schleife und concepts, dafür reif zur aufnahme: thread-lokale variablen und ein standardisiertes __attribute__.

_________________
quadrathelm? quadratuaheln!
1, 4, 9, 16, 25, usw.


Zuletzt bearbeitet von queer_boy am 20:50:57 31.05.2008, insgesamt 1-mal bearbeitet
ghorst
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.07.2007
Beiträge: 585
Beitrag ghorst Mitglied 13:35:05 03.06.2008   Titel:              Zitieren

also zuerst einmal: sehr guter artikel und vielen dank, dass du die änderungen für uns zusammengetragen hast.

nun zum eigentlichen: dass die concepts noch nicht teil des draft sind, finde ich ehrlich gesagt seltsam, da sie aus meiner sicht eine der sinnvollsten erweiterungen darstellen, da man zum einen endlich sinnvolle fehlermeldungen produzieren kann und zum anderen sich mit concept_map<> einen ganzen batzen adapterklassen sparen kann. ich hoffe, dass die doch noch reinkommen.


Zuletzt bearbeitet von ghorst am 12:32:14 04.06.2008, insgesamt 1-mal bearbeitet
HansiHinterseher
Unregistrierter




Beitrag HansiHinterseher Unregistrierter 14:54:28 03.06.2008   Titel:              Zitieren

Wo sollen sie sonst rein, wenn nicht in den Draft? Sie können nirgendwo besser rein, als dort. Dort wo du sie rein haben willst, können sie noch nicht rein, weil es den C++09-Standard noch garnicht gibt. Wer im Draft ist, ist so gut wie drin. Und drin ist man erst, wenns echte ISO-Norm geworden ist.
ghorst
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.07.2007
Beiträge: 585
Beitrag ghorst Mitglied 12:33:09 04.06.2008   Titel:              Zitieren

hmm. in meinem letzten beitrag fehlte ein nicht. jetzt ist es drin. die concepts sind eben noch nicht teil des draft und das stört mich.
queer_boy
Mitglied

Benutzerprofil
Anmeldungsdatum: 02.11.2006
Beiträge: 1035
Beitrag queer_boy Mitglied 22:50:43 05.06.2008   Titel:              Zitieren

aber so wie die momentane arbeitsverteilung des komitees aussieht, werden concepts wahrscheinlich bis zum oder knapp nach dem nächsten meeting drin sein, also keine sorge ;)

_________________
quadrathelm? quadratuaheln!
1, 4, 9, 16, 25, usw.
C++09
Unregistrierter




Beitrag C++09 Unregistrierter 13:12:07 06.06.2008   Titel:              Zitieren

Weiß jemand wie es mit dem Zeitplan nach C++09 aussieht?
Der TR2 soll ja zeitnah (was auch immer das bedeutet) folgen. Es soll dort wahrscheinlich eine Netzwerkbibliothek und ein Modulkonzept für C++ entwickelt werden. Wann soll TR2 eigentlich verabschiedet werden?
HansiHinterseher
Unregistrierter




Beitrag HansiHinterseher Unregistrierter 21:04:09 06.06.2008   Titel:              Zitieren

Für TR2 wurde Boost.asio und Boost.filesystem vorgeschlagen. Da denke ich, werden die das gebacken bekommen. Einen Termin gibt es denke ich nicht. Ich schätze mal, die werden das so in 2 bis 3 Jahren verabschieden.

Das Module reinkommen (wenn du damit dynamische Libs meinst?) bezweifel ich. Das werden die in 10 Jahren nicht schaffen... :(
C++09
Unregistrierter




Beitrag C++09 Unregistrierter 22:31:48 06.06.2008   Titel:              Zitieren

Die Netzwerkbibliothek war ja wirklich notwendig. Eigentlich nicht so schön das es noch dauert.
Mit Modulen meine ich das Paper von David Vandervoorde. Es gab Pläne es mit einem dynamischen Modulsystem (Plugins) zu kombinieren, so wie ich mitbekommen habe. Die Einschnitte in den C++ Standard sind aber wahrscheinlich zu groß als das man hier schnell etwas sehen wird. Denn das bedeutet faktisch die Anbschaffung des alten auf #include-Anweisungen basierenden Modulariesierungssystems - wenn man das überhaupt so nennen konnte ;) -. Aber interessant wäre es schon. Das würde Compilezeiten drastisch reduzieren, Namespace pollution
vermeiden und Sachen wie Whole Program Optimisation für Compiler Entwickler deutlich vereinfachen.
Scheinbar interessieren sich aber viele dafür weil es schon oft einem Peer-Review unterzogen wurde und in einen nachfolgenden TR aufgenommen werden soll, zumindest laut www.open-std.com
Zeus
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.09.2003
Beiträge: 2581
Beitrag Zeus Mitglied 00:56:27 07.06.2008   Titel:              Zitieren

HansiHinterseher schrieb:
Für TR2 wurde Boost.asio und Boost.filesystem vorgeschlagen. Da denke ich, werden die das gebacken bekommen. Einen Termin gibt es denke ich nicht. Ich schätze mal, die werden das so in 2 bis 3 Jahren verabschieden.

Das Module reinkommen (wenn du damit dynamische Libs meinst?) bezweifel ich. Das werden die in 10 Jahren nicht schaffen... :(


Module sollen ein neues Include-Methode sein. Evtl. hat es was mit den Libs gemeinsam, aber das weiss ich nicht. Module sind für den Standard nach C++09 vorgesehen.
Badestrand
Mitglied

Benutzerprofil
Anmeldungsdatum: 29.08.2006
Beiträge: 4342
Beitrag Badestrand Mitglied 11:17:40 07.06.2008   Titel:              Zitieren

Die Module hören sich interessant an, aber ich find leider nix dazu. Hat evtl jemand einen Link wie die Module aussehen?
C++09
Unregistrierter




Beitrag C++09 Unregistrierter 20:54:04 07.06.2008   Titel:              Zitieren

Das mit den Modulen hab ich hier her:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/#mailing2007-12
Den genauen Entwurf von Vandevoorde findest du hier:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2316.pdf (inzwischen Revision 5)
Badestrand
Mitglied

Benutzerprofil
Anmeldungsdatum: 29.08.2006
Beiträge: 4342
Beitrag Badestrand Mitglied 22:08:48 07.06.2008   Titel:              Zitieren

Cool, danke für die Links! Muss mich erstmal durch die 23 Seiten durcharbeiten, aber oberflächlich sieht's schonmal nett aus :live:
chris_
Unregistrierter




Beitrag chris_ Unregistrierter 08:53:19 19.07.2008   Titel:   sehr informativ, danke            Zitieren

Eine Anmerkung:
Sollte man das Beispiel:
C/C++ Code:
int foo ();
auto x2 = foo();
auto const& x3 = foo(); //auto kann mit cv-Qualifizierern, * und & verwendet werden
C/C++ Code:
int foo ();
auto x2 = foo();
auto const& x3 = foo(); //auto kann mit cv-Qualifizierern, * und & verwendet werden
C/C++ Code:
int foo ();
auto x2 = foo();
auto const& x3 = foo(); //auto kann mit cv-Qualifizierern, * und & verwendet werden

nicht besser so umschreiben, dass x3 keine Referenz auf eine temporäre Variable ist?

Vielleicht einfach
C/C++ Code:
auto const& x3 = x2;
C/C++ Code:
auto const& x3 = x2;
C/C++ Code:
auto const& x3 = x2;
Optimizer
Mitglied

Benutzerprofil
Anmeldungsdatum: 19.09.2002
Beiträge: 8317
Beitrag Optimizer Mitglied 10:54:14 19.07.2008   Titel:              Zitieren

C++09 schrieb:
Die Netzwerkbibliothek war ja wirklich notwendig. Eigentlich nicht so schön das es noch dauert.
Mit Modulen meine ich das Paper von David Vandervoorde. Es gab Pläne es mit einem dynamischen Modulsystem (Plugins) zu kombinieren, so wie ich mitbekommen habe. Die Einschnitte in den C++ Standard sind aber wahrscheinlich zu groß als das man hier schnell etwas sehen wird. Denn das bedeutet faktisch die Anbschaffung des alten auf #include-Anweisungen basierenden Modulariesierungssystems - wenn man das überhaupt so nennen konnte ;) -. Aber interessant wäre es schon. Das würde Compilezeiten drastisch reduzieren, Namespace pollution
vermeiden und Sachen wie Whole Program Optimisation für Compiler Entwickler deutlich vereinfachen.
Scheinbar interessieren sich aber viele dafür weil es schon oft einem Peer-Review unterzogen wurde und in einen nachfolgenden TR aufgenommen werden soll, zumindest laut www.open-std.com
Ich bezweifle, dass es die Sache für Compilerentwickler vereinfachen wird, da sie den alten Mist trotzdem unterstützen müssen. Aber die Programmierer werden davon natürlich profitieren, weil neue Libs u.U. dieses Feature dann nutzen. Die Compilerbauer tun mir echt langsam leid. Es kommt immer neues freakiges Zeug hinzu, dabei ist offensichtlich, dass sie jetzt schon überfordert sind. :(

Ich freue mich jedenfalls trotzdem darauf. :) Ich hoffe, dass zumindest für den nächsten Standard die Concepts noch kommen.

_________________
Nichts zu verbergen™ - dein Beitrag zum Krieg gegen den Terrorismus!
Bashar
Mitglied

Benutzerprofil
Anmeldungsdatum: 15.05.2001
Beiträge: 16812
Beitrag Bashar Mitglied 10:58:28 19.07.2008   Titel:              Zitieren

Optimizer schrieb:
Die Compilerbauer tun mir echt langsam leid. Es kommt immer neues freakiges Zeug hinzu, dabei ist offensichtlich, dass sie jetzt schon überfordert sind. :(

Warum votieren sie dann nicht dagegen? Der Standardisierungsprozess läuft ja nicht gerade hinter verschlossenen Türen ab.

_________________
OSL♥
Optimizer
Mitglied

Benutzerprofil
Anmeldungsdatum: 19.09.2002
Beiträge: 8317
Beitrag Optimizer Mitglied 11:05:30 19.07.2008   Titel:              Zitieren

Naja ich rede von den Code-Sklaven, die im -87ten Stock im Microsoft-Campus eingesperrt sind. :o) Das sind nicht die Leute, die offiziell die Position vom MS (insert beliebige Firma here) vertreten. Überhaupt bin ich mir nicht sicher, ob sie die Änderungen ablehnen würden - ich sag nur, sie tun mir leid.

_________________
Nichts zu verbergen™ - dein Beitrag zum Krieg gegen den Terrorismus!
Zeus
Mitglied

Benutzerprofil
Anmeldungsdatum: 25.09.2003
Beiträge: 2581
Beitrag Zeus Mitglied 11:39:30 19.07.2008   Titel:              Zitieren

Bashar schrieb:
Optimizer schrieb:
Die Compilerbauer tun mir echt langsam leid. Es kommt immer neues freakiges Zeug hinzu, dabei ist offensichtlich, dass sie jetzt schon überfordert sind. :(

Warum votieren sie dann nicht dagegen? Der Standardisierungsprozess läuft ja nicht gerade hinter verschlossenen Türen ab.


Weil die Veränderungen ihre Arbeitstelle sichert :D


Zuletzt bearbeitet von Zeus am 11:39:41 19.07.2008, insgesamt 1-mal bearbeitet
sinamine
Mitglied

Benutzerprofil
Anmeldungsdatum: 23.07.2008
Beiträge: 1
Beitrag sinamine Mitglied 08:24:53 23.07.2008   Titel:              Zitieren

Zitat:
UTF-16-String-Literale. Eingeleitet werden diese mit dem Präfix u. Die dahinterstehende Kodierung ist UTF-16 und der Typ der Literale ist "Array von n const char16_t". char16_t ist ein neu eingeführter Typ mit der Kodierung UTF-16, der im Header <cuchar> definiert ist.


Wollte fragen, ob ich mir mit diesem Typ die Konvertierung sparen kann? D.h. wenn ich UTF-16 Daten mit komplexen Zeichen einlese, konvertiert mir char16_t die Daten automatisch nach UTF-16?

Bis wann genau werden die gesamten Erneuerungen zur Verfügung stehen? Und wie sieht es aus mit "Polymorphic Function Objects" welche im TR1 beschrieben sind. Bis wann wird man diese Erneuerungen nutzen können?

Dann wollte ich noch fragen, ob es irgendwelche Erneuerungen bezüglich Objekte zeichnen gibt. Also ob es ander Möglichkeiten gibt um eine Linie oder ein Rechteck zu zeichnen - also ein Kollege meinte, dass es Erneuerungen gibt bzw. geben wird, aber ich habe noch nicht wirklich etwas darüber gefunden! Wäre super wenn ihr mir weiterhelfen könntet!


Zuletzt bearbeitet von sinamine am 08:53:11 23.07.2008, insgesamt 1-mal bearbeitet
Compiler-Bauer
Unregistrierter




Beitrag Compiler-Bauer Unregistrierter 23:06:08 01.08.2008   Titel:              Zitieren

Warum sollten wir etwas dagegen haben? Wir bekommen ja schließlich Geld dafür :p
queer_boy
Mitglied

Benutzerprofil
Anmeldungsdatum: 02.11.2006
Beiträge: 1035
Beitrag queer_boy Mitglied 02:42:19 02.08.2008   Titel:              Zitieren

sinamine schrieb:
Zitat:
UTF-16-String-Literale. Eingeleitet werden diese mit dem Präfix u. Die dahinterstehende Kodierung ist UTF-16 und der Typ der Literale ist "Array von n const char16_t". char16_t ist ein neu eingeführter Typ mit der Kodierung UTF-16, der im Header <cuchar> definiert ist.


Wollte fragen, ob ich mir mit diesem Typ die Konvertierung sparen kann? D.h. wenn ich UTF-16 Daten mit komplexen Zeichen einlese, konvertiert mir char16_t die Daten automatisch nach UTF-16?

ich weiß jetzt leider nicht aus dem stehgreif, ob es standard-streams gibt, die daten automatisch als UTF-16 einlesen können (basic_iostream<char16_t>), aber im prinzip stünde dem nichts im wege. char16_t werden eben, ganz un-standard-mäßig gesprochen, 2-byte-oder-mehr-character sein, die für UTF-16 ausreichend platz bieten, mehr nicht.

Zitat:

Bis wann genau werden die gesamten Erneuerungen zur Verfügung stehen? Und wie sieht es aus mit "Polymorphic Function Objects" welche im TR1 beschrieben sind. Bis wann wird man diese Erneuerungen nutzen können?

bis wann? die sachen, die im TR1 beschrieben sind, werden beinahe wortwörtlich in den neuen standard übernommen werden. die funktionen rund um std::bind sind durch boost schon seit langem verfügbar und werden eben obligatorisch.

Zitat:

Dann wollte ich noch fragen, ob es irgendwelche Erneuerungen bezüglich Objekte zeichnen gibt. Also ob es ander Möglichkeiten gibt um eine Linie oder ein Rechteck zu zeichnen - also ein Kollege meinte, dass es Erneuerungen gibt bzw. geben wird, aber ich habe noch nicht wirklich etwas darüber gefunden! Wäre super wenn ihr mir weiterhelfen könntet!

hm. andere möglichkeiten? bis jetzt hat der standard nicht definiert, was linien oder rechtecke sind, d.h. du wirst bis jetzt immer irgendein toolkit verwendet haben, das diese funktionen zur verfügung stellt.
zur grafischen ausgabe sagt der neue standard gar nichts (so wie der alte).

_________________
quadrathelm? quadratuaheln!
1, 4, 9, 16, 25, usw.
queer_boy
Mitglied

Benutzerprofil
Anmeldungsdatum: 02.11.2006
Beiträge: 1035
Beitrag queer_boy Mitglied 14:57:33 20.11.2008   Titel:              Zitieren

so, eine info: hab vor kurzem einige updates mithilfe des neuen working-drafts hier (und im anderen artikel) vorgenommen. C++0x ist nun feature complete und es dürfte wohl viele leute freuen, dass alle features, die hier vorgestellt werden, auch wahrscheinlich in dieser form, teil von C++0x werden. (ob C++0x nun C++09 wird oder C++0A steht zwar noch in den sternen, aber ich bin zuversichtlich :) )

_________________
quadrathelm? quadratuaheln!
1, 4, 9, 16, 25, usw.
Optimizer
Mitglied

Benutzerprofil
Anmeldungsdatum: 19.09.2002
Beiträge: 8317
Beitrag Optimizer Mitglied 16:34:29 20.11.2008   Titel:              Zitieren

Da gab's doch in diesem Komitee einen Kerl, der gegen alles gevoted hat was Concepts angeht, mit der Begründung dass er befürchtet, dass es zu unausgereift ist und hier ein falscher Grundstein gelegt wird. Weiß man genaueres darüber, was seine Befürchtungen sind?

_________________
Nichts zu verbergen™ - dein Beitrag zum Krieg gegen den Terrorismus!
queer_boy
Mitglied

Benutzerprofil
Anmeldungsdatum: 02.11.2006
Beiträge: 1035
Beitrag queer_boy Mitglied 04:14:35 21.11.2008   Titel:              Zitieren

das war david vandevoorde (der sich mit templates ja wirklich gut auskennt), was genaueres weiß ich auch nicht, aber das könnte man ja einmal in comp.lang.c++.moderated besprechen.

_________________
quadrathelm? quadratuaheln!
1, 4, 9, 16, 25, usw.
Purrrfect
Unregistrierter




Beitrag Purrrfect Unregistrierter 22:48:08 02.05.2009   Titel:              Zitieren

Ich habe eine Frage zu den variadic templates. Wenn ich als template-Argumente eine Liste von ints habe, möchte ich ja auch auf die einzelnen Einträge zugreifen können. Geht also sowas wie:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
1
2
3
4
5
6
7
8
9
10
11
12
13
14
template <int ...x> struct foo
{
  static const int bar[sizeof...(x)] = { x... };
  const int operator[](const int i)
  {
    return bar[i];
  }
};

int main()
{
  foo<0, 0, 0> f;
  return f[1];
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
template <int ...x> struct foo
{
static const int bar[sizeof...(x)] = { x... };
const int operator[](const int i)
{
return bar[i];
}
};

int main()
{
foo<0, 0, 0> f;
return f[1];
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
template <int ...x> struct foo
{
  static const int bar[sizeof...(x)] = { x... };
  const int operator[](const int i)
  {
    return bar[i];
  }
};

int main()
{
  foo<0, 0, 0> f;
  return f[1];
}

Oder gibt es eine andere Möglichkeit? :confused:
EinBAStudentDerNichtLernt
Unregistrierter




Beitrag EinBAStudentDerNichtLernt Unregistrierter 15:16:49 03.05.2009   Titel:              Zitieren

Purrrfect schrieb:
Ich habe eine Frage zu den variadic templates. Wenn ich als template-Argumente eine Liste von ints habe, möchte ich ja auch auf die einzelnen Einträge zugreifen können. Geht also sowas wie:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
1
2
3
4
5
6
7
8
9
10
11
12
13
14
template <int ...x> struct foo
{
  static const int bar[sizeof...(x)] = { x... };
  const int operator[](const int i)
  {
    return bar[i];
  }
};

int main()
{
  foo<0, 0, 0> f;
  return f[1];
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
template <int ...x> struct foo
{
static const int bar[sizeof...(x)] = { x... };
const int operator[](const int i)
{
return bar[i];
}
};

int main()
{
foo<0, 0, 0> f;
return f[1];
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
template <int ...x> struct foo
{
  static const int bar[sizeof...(x)] = { x... };
  const int operator[](const int i)
  {
    return bar[i];
  }
};

int main()
{
  foo<0, 0, 0> f;
  return f[1];
}

Oder gibt es eine andere Möglichkeit? :confused:

Früher war afaik der Syntax [].[index] im Gespräch - afaik ist der aber nicht durchgekommen.
Deine Möglichkeit wär' wohl möglich - schöner wär aber was mit constexpr...
Daveed Vandevoorde
Unregistrierter




Beitrag Daveed Vandevoorde Unregistrierter 23:13:13 06.05.2009   Titel:   My position on concepts            Zitieren

queer_boy schrieb:
das war david vandevoorde (der sich mit templates ja wirklich gut auskennt), was genaueres weiß ich auch nicht, aber das könnte man ja einmal in comp.lang.c++.moderated besprechen.


Please forgive me for responding in English: I don't write German.

Here is my position on C++0x concepts. It's an interesting feature, but it is currently unimplemented. There is a partial implementation (ConceptGCC) of an earlier specification, but what was voted in the working paper is significantly different. That brings about a fair number of risks, in my opinion:
- Potentially breaking significant existing code (because of library changes) in ways we are not aware of.
- Potentially being programmer-unfriendly (i.e., I worry that I might more often than not find writing a constrained template to be an unpleasant affair).
- Potentially have an excessive number of semantic holes (i.e., having to significantly revise/extend the specification long after the language standard has been published).
- Potentially being excessively expensive to implement.

Note that I'm not saying that "C++0x concepts are a bad idea"; instead I say "There is -- in my opinion -- insufficient evidence that the current incarnation of C++0x concepts is a well-executed good idea".

Part of the problem here is that we're dealing with a very large feature that is essentially added "all at once" to the language. (Compare that to the original templates, which were added to the language by bits and pieces, and then eventually standardized after we had industrial experience with most of it.)

Hopefully, my worries will turn out to be unfounded.

Daveed
Sebastian Pizer
Unregistrierter




Beitrag Sebastian Pizer Unregistrierter 21:59:15 24.05.2009   Titel:   Anregungen, Verbesserungsvorschläge            Zitieren

Hallo, queer_boy! Meinen Respekt für die Arbeit, die du in den Artikel gesteckt hast.

Hier sind ein paar Anregungen und Verbesserungsvorschläge:

Zu Variadischen Templates: Man könnte noch erwähnen, dass der eingebaute "sizeof..."-operator eigentlich ein template a la count_args<>::value erspart. Das 3. Codebeispiel scheint einen copy/paste Fehler zu enthalten. Statt
C/C++ Code:
template <class T, class ...Args>
T* make_new (Args&& ...args)
{
   //expandiert automatisch richtig:
   return new T( *new Args(static_cast<Args&&>(args)) ...);
}
C/C++ Code:
template <class T, class ...Args>
T* make_new (Args&& ...args)
{
//expandiert automatisch richtig:
return new T( *new Args(static_cast<Args&&>(args)) ...);
}
C/C++ Code:
template <class T, class ...Args>
T* make_new (Args&& ...args)
{
   //expandiert automatisch richtig:
   return new T( *new Args(static_cast<Args&&>(args)) ...);
}

müsste es doch eigentlich heißen
C/C++ Code:
template <class T, class ...Args>
T* make_new (Args&& ...args)
{
   //expandiert automatisch richtig:
   return new T(static_cast<Args&&>(args)...);
}
C/C++ Code:
template <class T, class ...Args>
T* make_new (Args&& ...args)
{
//expandiert automatisch richtig:
return new T(static_cast<Args&&>(args)...);
}
C/C++ Code:
template <class T, class ...Args>
T* make_new (Args&& ...args)
{
   //expandiert automatisch richtig:
   return new T(static_cast<Args&&>(args)...);
}

oder nicht?

Zu Rvalue-Referenzen: Das Beispiel "Optimierungen von std::string" wird nach den neuen Regeln nicht kompilieren und ist auch nicht wirklich im Sinne der Spracherweiterung. Das Zurückgeben von Referenzen birgt die Gefahr von "baumelnden Referenzen". Nach den neuen Regeln binden Rvalue-Referenzen auch keine Lvalues mehr. Aber das, was Du zurückgiebst sind Lvalue-Ausdrücke. In neueren Beispielen findet man soetwas:
C/C++ Code:
string operator+(string && a, string const& b)
{
  a += b;
  return move(a);
}
C/C++ Code:
string operator+(string && a, string const& b)
{
a += b;
return move(a);
}
C/C++ Code:
string operator+(string && a, string const& b)
{
  a += b;
  return move(a);
}

Das move() ist hier notwendig, weil 'a' ein Referenz-Parameter ist, der wie ein Lvalue-Ausdruck behandelt wird. (Das move() ist aber bei lokalen Variablen überflüssig und sollte vermieden werden, weil es die NRV-Optimierung des Compilers umgehen könnte).

Neue Funktions-Syntax: Ich glaube nicht, dass Deine typedefs und die Deklaration des Arrays a korrekt sind. Der Deklarator sitzt da an der falschen Stelle:
C/C++ Code:
typedef (auto (int) -> int) F; // Falsch
typedef auto F(int) -> int;    // Richtig
C/C++ Code:
typedef (auto (int) -> int) F; // Falsch
typedef auto F(int) -> int; // Richtig
C/C++ Code:
typedef (auto (int) -> int) F; // Falsch
typedef auto F(int) -> int;    // Richtig


Lambdas: Soweit ich weiß, fehlt da bei dem einen oder anderen Lambda-Ausdruck die Return-Anweisung und/oder ein Semikolon. Einige Klammern sind auch falsch. Beispiel:
C/C++ Code:
int i = [](int x, int y) (x + y) (42,23);       // Falsch
int i = [](int x, int y) {return x+y;} (42,23); // Richtig
C/C++ Code:
int i = [](int x, int y) (x + y) (42,23); // Falsch
int i = [](int x, int y) {return x+y;} (42,23); // Richtig
C/C++ Code:
int i = [](int x, int y) (x + y) (42,23);       // Falsch
int i = [](int x, int y) {return x+y;} (42,23); // Richtig


Das war's erstmal von mir.

Gruß,
Sebastian
Badestrand
Mitglied

Benutzerprofil
Anmeldungsdatum: 29.08.2006
Beiträge: 4342
Beitrag Badestrand Mitglied 10:48:32 07.06.2009   Titel:              Zitieren

Ich probiere gerade die Beta1 vom VS 2010 aus, mal eine Frage: Kann man die Lambda-Funktionen eigentlich "ordentlich" übergeben? Mit VS klappt sowas:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
template<typename T>
void whatever( T calc )
{
    std::cout << calc( 10 ) << std::endl;
}

int main()
{
    whatever( [](int x)->int {return x*2;} );
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
template<typename T>
void whatever( T calc )
{
std::cout << calc( 10 ) << std::endl;
}

int main()
{
whatever( [](int x)->int {return x*2;} );
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
template<typename T>
void whatever( T calc )
{
    std::cout << calc( 10 ) << std::endl;
}

int main()
{
    whatever( [](int x)->int {return x*2;} );
}


Würde gerne den Typ angeben (also zumindest Parameter-Anzahl), konnte dazu im Artikel aber nichts finden.
Wikinger75
Mitglied

Benutzerprofil
Anmeldungsdatum: 17.01.2009
Beiträge: 376
Beitrag Wikinger75 Mitglied 13:18:49 07.06.2009   Titel:              Zitieren

Kleine frage noch.
Ich glaube das das auhc noch dazu gehört^^

In C hat man ja die endungen C & H benutzt für Quellcode daten und header
in C++ wurden folgende mit eingeeführt: CPP & HPP.
Jedoch habe ich auch CXX und HXX gefunden, haben diese ihren ursprung aus dem C++0x Standard oder wo kommen diese her?

Mfg Wikinger75!
Sebastian Pizer
Unregistrierter




Beitrag Sebastian Pizer Unregistrierter 16:27:45 12.06.2009   Titel:   lambdas und std::function            Zitieren

Badestrand schrieb:
Ich probiere gerade die Beta1 vom VS 2010 aus, mal eine Frage: Kann man die Lambda-Funktionen eigentlich "ordentlich" übergeben? Mit VS klappt sowas:
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
template<typename T>
void whatever( T calc )
{
    std::cout << calc( 10 ) << std::endl;
}

int main()
{
    whatever( [](int x)->int {return x*2;} );
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
template<typename T>
void whatever( T calc )
{
std::cout << calc( 10 ) << std::endl;
}

int main()
{
whatever( [](int x)->int {return x*2;} );
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
template<typename T>
void whatever( T calc )
{
    std::cout << calc( 10 ) << std::endl;
}

int main()
{
    whatever( [](int x)->int {return x*2;} );
}


Würde gerne den Typ angeben (also zumindest Parameter-Anzahl), konnte dazu im Artikel aber nichts finden.


Ein Lambda-Ausdruck generiert ein Objekt eines einzigartigen aber anonymen Typs. Die Template-Parameter-Herleiting des Compilers ist das einzige, was Dich direkt ein Lambdaobjekt halten lässt. Das schlißt auch "auto" mit ein:
C/C++ Code:
int main()
{
    auto f = [](int x)->int {return x*2;};
    whatever( f );
}
C/C++ Code:
int main()
{
auto f = [](int x)->int {return x*2;};
whatever( f );
}
C/C++ Code:
int main()
{
    auto f = [](int x)->int {return x*2;};
    whatever( f );
}


Du kannst aber so ein Funktionsobjekt mit Hilfe der "Type Erasure"-Technik in einem anderen Funktionsobjekt kapseln. Dazu ist das Bibliotheks-Feature "std::function" gedacht:

C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
1
2
3
4
5
6
7
8
9
10
11
#include <functional>

void whatever( std::function<int(int)> calc )
{
    std::cout << calc( 10 ) << std::endl;
}

int main()
{
    whatever( [](int x)->int {return x*2;} );
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
#include <functional>

void whatever( std::function<int(int)> calc )
{
std::cout << calc( 10 ) << std::endl;
}

int main()
{
whatever( [](int x)->int {return x*2;} );
}
C/C++ Code:
1
2
3
4
5
6
7
8
9
10
11
#include <functional>

void whatever( std::function<int(int)> calc )
{
    std::cout << calc( 10 ) << std::endl;
}

int main()
{
    whatever( [](int x)->int {return x*2;} );
}


Hier wird das Lambda-Objekt implizit zu einem std::function<int(int)> objekt konvertiert. Hinter dem Vorhang läuft das mit Laufzeit-Polymorphie (abstrakte Basis-Klasse mit virtuellen Funktionen). Man kann aber davon ausgehen, dass eine qualitativ gute Implementierung von std::function sehr effizient bei "kleinen" Funktionsobjekten funktioniert. In diesem Fall hat Dein Lambda-Objekt gar keinen "Zustand". Es sollte also von der "small-function-optimization" profitieren. Bei großen Funktionsobjekten muss man hier auf den Freispeicher ausweichen.

Bis vor kurzem gab es noch eine andere Möglichkeit, Lambda-Objekte, die entweder gar nichts einfangen oder alle Variablen im umliegenden Geltungsbereich per Referenz fangen: reference_closure<>. Dieser Ansatz war aber nicht viel besser als std::function. Er wurde deswegen wieder aus dem Entwurf genommen.

Gruß,
Sebastian
Sebastian Pizer
Unregistrierter




Beitrag Sebastian Pizer Unregistrierter 16:37:21 12.06.2009   Titel:              Zitieren

Wikinger75 schrieb:
Kleine frage noch.
In C hat man ja die endungen C & H benutzt für Quellcode daten und header
in C++ wurden folgende mit eingeeführt: CPP & HPP.
Jedoch habe ich auch CXX und HXX gefunden, haben diese ihren ursprung aus dem C++0x Standard oder wo kommen diese her?

Das sind lediglich Konventionen. Die Endungen der Dateinamen sind nicht standartisiert. CXX und HXX gabs vor C++0x auch schon. :)

Gruß,
Sebastian
Badestrand
Mitglied

Benutzerprofil
Anmeldungsdatum: 29.08.2006
Beiträge: 4342
Beitrag Badestrand Mitglied 16:41:56 12.06.2009   Titel:              Zitieren

Sebastian Pizer schrieb:
Du kannst aber so ein Funktionsobjekt mit Hilfe der "Type Erasure"-Technik in einem anderen Funktionsobjekt kapseln. Dazu ist das Bibliotheks-Feature "std::function" gedacht

Perfekt, danke! Und danke auch für die Erklärungen drumherum. Das Komitee hat wirklich verflucht gute Arbeit geleistet :live:
heinrich5991
Unregistrierter




Beitrag heinrich5991 Unregistrierter 18:57:23 15.07.2009   Titel:   Syntax            Zitieren

Ein paar neue Prinzipien finde ich gut, aber dass viel zu viele meiner Meinung nach sinnlos. Ich weiß nicht, was ich insgesamt davon halten soll.
rüdiger
Moderator

Benutzerprofil
Anmeldungsdatum: 11.07.2001
Beiträge: 22819
Beitrag rüdiger Moderator 18:57:12 09.08.2009   Titel:              Zitieren

Ist vermutlich schon bekannt. Aber der Vollständigkeit halber: Concepts wurden aus dem Draft wieder entfernt und werden kein Bestandteil von C++0x werden.

Bjarne Stroustrup erklärt warum http://www.ddj.com/cpp/218600111

Und hier noch ein Artikel von Doug Gregor dazu: http://cpp-next.com/archive/2009/08/what-happened-in-frankfurt/

_________________
.


Zuletzt bearbeitet von rüdiger am 19:01:48 09.08.2009, insgesamt 1-mal bearbeitet
phlox81
Moderator

Benutzerprofil
Anmeldungsdatum: 21.04.2001
Beiträge: 7208
Beitrag phlox81 Moderator 00:50:38 20.03.2010   Titel:              Zitieren

Neues von C++0x:

http://herbsutter.wordpress.com/2010/03/13/trip-report-march-2010-iso-c-standards-meeting/

_________________
Intelligenz ist eine Illusion des Menschen

phlox81.de | The Black Board | Code Node | Xing | Blog | Twitter
C/C++ Forum :: Die Artikel ::  C++09 (Teil 1) - Ein Überblick: Sprachfeatures   Auf Beitrag antworten

Zeige alle Beiträge auf einer Seite




Nächstes Thema anzeigen
Vorheriges Thema anzeigen
Sie können keine Beiträge in dieses Forum schreiben.
Sie können auf Beiträge in diesem Forum antworten.
Sie können Ihre Beiträge in diesem Forum nicht bearbeiten.
Sie können Ihre Beiträge in diesem Forum nicht löschen.
Sie können an Umfragen in diesem Forum nicht mitmachen.

Powered by phpBB © 2001, 2002 phpBB Group :: FI Theme

c++.de ist Teilnehmer des Partnerprogramms von Amazon Europe S.à.r.l. und Partner des Werbeprogramms, das zur Bereitstellung eines Mediums für Websites konzipiert wurde, mittels dessen durch die Platzierung von Werbeanzeigen und Links zu amazon.de Werbekostenerstattung verdient werden kann.

Die Vervielfältigung der auf den Seiten www.c-plusplus.de, www.c-plusplus.info, www.c-sar.de, www.c-plusplus.net und www.baeckmann.de enthaltenen Informationen ohne eine schriftliche Genehmigung des Seitenbetreibers ist untersagt (vgl. §4 Urheberrechtsgesetz). Die Nutzung und Änderung der vorgestellten Strukturen und Verfahren in privaten und kommerziellen Softwareanwendungen ist ausdrücklich erlaubt, soweit keine Rechte Dritter verletzt werden. Der Seitenbetreiber übernimmt keine Gewähr für die Funktion einzelner Beiträge oder Programmfragmente, insbesondere übernimmt er keine Haftung für eventuelle aus dem Gebrauch entstehenden Folgeschäden.