Open Source im professionellen Einsatz

Automatik und Typ-Erkennung

Das Ausführen des fertigen Programms aus Listing 5 führt zur Ausgabe »myAdd(1,2): 3«. Neben »auto«, das den Typ aus einem Initializer ableitet, enthält C++0x noch das Schlüsselwort »decltype«, das den Typ aus einem Ausdruck ermittelt. Es ist ein mächtiges Werkzeug in generischen Kontexten, in denen der Ergebnistyp aus einer Operation nur schwer zu ermitteln ist. Der Ausdruck »decltype(myVecInt[0]*myDoubleInt[0]) myDouble« deklariert in Listing 6 »myDouble« vom Typ »double«.

Weiter geht es mit Neuerungen zum generischen Programmieren: Variadic Templates können mit einer beliebigen Zahl von Template-Argumenten umgehen. Ein praktisches Beispiel: Listing 7 verwendet Variadic Templates. Die Template-Funktion »f()« nimmt beliebig viele Argumente an und gibt deren Anzahl zurück. »printCommaSeparatedList()« erwartet ein oder mehrere Argumente und gibt diese kommasepariert aus.

Abbildung 4 zeigt die Ausgabe des Programms. Das Entscheidende sind die drei Punkte, die entweder links in »template <typename... Args>« oder in »int f(Args... args){« rechts vom Parameter »Args« stehen. Links packt der Ellipsen-Operator »...« das so genannte Parameter Pack, rechts entpackt er es wieder. Eine Besonderheit ist der neue Operator »sizeof ...« (Zeile 7), der direkt mit Parameter Packs umgehen kann.

Abbildung 4: Variadic Templates können mit einer beliebigen Zahl von Argumenten umgehen – die Ausgabe von Listing 7.

Abbildung 4: Variadic Templates können mit einer beliebigen Zahl von Argumenten umgehen – die Ausgabe von Listing 7.

Listing 7: Variadic
Templates

01 #include <iostream>
02 #include <string>
03 #include <vector>
04 
05 template <typename... Args>
06 int f(Args... args){
07   return (sizeof... args);
08 }
09 
10 template<typename T>
11 void printCommaSeparatedList(T value)
12 {
13   std::cout<<value<<std::endl;
14 }
15 
16 template<typename First,typename ... Rest>
17 void printCommaSeparatedList(First first,Rest ... rest)
18 {
19   std::cout<<first<<",";
20   printCommaSeparatedList(rest...);
21 }
22 
23 
24 int main() {
25   std::cout << "n";
26 
27   auto intList= {1,2,3};
28   std::vector <int> intVec= {1,2,3,4,5};
29 
30   std::cout << "f() has " << f() << " argumentsn";
31   std::cout << "f(42, 3.14) has " << f(42, 3.14) << " argumentsn";
32   std::cout << "f("one","two","three","four") has " << f("one","two","three","four" ) << " argumentsn";
33   std::cout << "f(intVec,intList) has " << f(intVec,intList) << " argumentsnn";
34 
35   printCommaSeparatedList("Only primary template used.");
36   printCommaSeparatedList(42,"hello",2.3,'a');
37   std::cout << "n";
38 }

Listing 8:
Compilezeit-Konstanten

01 constexpr int square(int x) { return x * x; }
02 int values[square(7)];

Rekursion

Deutlich ungewohnter zeigt sich die Template-Funktion »printCommaSeparatedList()«. Sie besteht aus dem Template in Zeile 10, das nur ein Argument erwartet und dem gleichnamigen Template in Zeile 16, das mehr als ein Argument erwartet. Beim Aufruf mit einem einzigen Argument, beispielsweise mit

printCommaSeparatedList("Only primary U template used.");

kommt das Template mit einem Argument zum Einsatz und gibt den String aus. Dagegen stößt der Aufruf

printCommaSeparatedList(42,"hello",2.3,'a');

die Rekursion an, gibt das erste Argument mit der Anweisung »std::cout <<first<<",";« aus und ruft sich rekursiv mit der Anweisung »printCommaSeparatedList(rest...);« auf. Dieser Prozess kommt genau dann zum Erliegen, wenn »rest« nur noch ein Element enthält, denn jetzt wird das Template mit einem Argument verwendet.

Pattern Matching und rekursive Aufrufe sind elementare Bausteine der funktionalen Programmierung [8]. Ein interessanteres Beispiel für Variadic Templates ist die Funktion »printf()« [9]: Im Gegensatz zu ihrem C-Pendant ist sie typsicher.

Die Technik Template Metaprogramming [10] zeichnet sich dadurch aus, dass der Code zur Compilezeit ausgeführt wird und somit zur Laufzeit bereits als Konstante zur Verfügung steht.

Damit das funktioniert, müssen sich die Ausdrücke zur Compilezeit evaluieren lassen. Genau dies bewirkt das neue Schlüsselwort »constexpr« in Listing 8. Damit lassen sich einfache Funktionen, die einen Return-Wert besitzen, sowie auch Objekte auswerten. Das Array in Listing 7 beispielsweise lässt sich in C++0x über die Compilezeit-Konstante initialisieren. Die genaueren Forderungen an »constexpr« sind im Wikipedia-Eintrag unter [11] nachzulesen.

Das Schlüsselwort »static_assert« macht es möglich, konstante Ausdrücke ohne die Magie des Template Metaprogramming zur Compilezeit zu evaluieren. Dies ist besonders hilfreich, weil der Programmierer mit »static_assert« Voraussetzungen für die Templateparameter prüfen kann. Der Ausdruck

static_assert(sizeof(int) == 4, "This code U only works for sizeof(int) == 4");

stellt sicher, dass »int« die richtige Größe besitzt, und führt im Fehlerfall dazu, dass das Kompilieren abbricht und der String »"This code only works for sizeof(int) == 4")« ausgegeben wird.

Diesen Artikel als PDF kaufen

Express-Kauf als PDF

Umfang: 5 Heftseiten

Preis € 0,99
(inkl. 19% MwSt.)

Als digitales Abo

Als PDF im Abo bestellen

comments powered by Disqus

Ausgabe 07/2013

Preis € 6,40

Insecurity Bulletin

Insecurity Bulletin

Im Insecurity Bulletin widmet sich Mark Vogelsberger aktuellen Sicherheitslücken sowie Hintergründen und Security-Grundlagen. mehr...

Linux-Magazin auf Facebook