Entdecken Sie eBooks
Kategorien
Entdecken Sie Hörbücher
Kategorien
Entdecken Sie Zeitschriften
Kategorien
Entdecken Sie Dokumente
Kategorien
Winersemester 2011/2012 Fachgruppe Mathematik und Informatik FB C Bergische Universita t Wuppertal Praktische Informatik PIBUW - WS11/12 Oktober 2011 2. Auage, 2011
ii
Inhaltsverzeichnis
1 Generische Programmierung 7 1.1 Was ist generische Programmierung? . . . . . . . . . . . . . . . . . . . . 7 1.2 Beispiel einer generische Funktion mit einem generischen Parameter . . . 7 1.3 Benutzung von std::swap() . . . . . . . . . . . . . . . . . . . . . . . . . 8 1.4 Einsatzgebiete und Beispielrepositorien f ur generische Konstrukte: die STL, ... 9 1.5 Instanzen generischer Objekte . . . . . . . . . . . . . . . . . . . . . . . . 10 1.5.1 Objekt-Dateien: wo sind welche Instanzen meiner generischen Objekte (nm und c++lt)? 1.5.2 Erstellen und Benutzen von statischen Bibliotheken . . . . . . . . 21 1.5.3 Erstellen und Benutzen einer shared object- Bibliothek . . . . . 24 1.5.4 Bibliotheksmanagement insbesondere unter verschiedenen Betriebssystemen 25 1.6 STL-Templatequellen unter SuSE-Linux f urs zeilenweise Debuggen auch innerhalb der STL-Routin 1.7 Automatisch u ufte Requirements an Template-Parameter . . . . . . 27 berpr 1.7.1 mit Hilfe von BOOST STATIC ASSERT() . . . . . . . . . . . . . 29 1.7.2 mit Hilfe des c++0x-Modus des g++ . . . . . . . . . . . . . . . . 30 1.8 horrible error messages bei STL-Nutzung . . . . . . . . . . . . . . . . . 31 1.8.1 C++11 type traits . . . . . . . . . . . . . . . . . . . . . . . . . . 33 1.8.2 BOOST type traits . . . . . . . . . . . . . . . . . . . . . . . . . . 33 1.8.3 numeric limits als Typ-Abbildung . . . . . . . . . . . . . . . . . . 34 1.9 Template-Deklarationen zur Erzeugung von Objektdateien mit einer Ansammlung von Template-I 1.10 Die Boost-Bibliothek . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 1.11 Wo ist die Template-Instanz? . . . . . . . . . . . . . . . . . . . . . . . . 37 1.12 C++11 extern template . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 1.13 Orte, wo statische Zusicherungen benutzt werden . . . . . . . . . . . . . 37 1.14 Fehlermeldungen bei uneingeschr ankter Generizit at . . . . . . . . . . . . 38 1.15 Verbesserte Fehlermeldungen bei Nutzung von StaticAssert . . . . . . . . 41 1.15.1 RandomAccessIterator . . . . . . . . . . . . . . . . . . . . . . . . 41 1.15.2 Nicht instantiierbare Klassen . . . . . . . . . . . . . . . . . . . . . 44 1.15.3 Erzwingung gleicher Typen . . . . . . . . . . . . . . . . . . . . . 45 1.15.4 Funktionen mit (int/oat/...) type promotion . . . . . . . . . . . 46 1.15.5 Auf Unterklassen eingeschr ankte Generizit at . . . . . . . . . . . . 46 1.15.6 Uberladene Templatefunktionen . . . . . . . . . . . . . . . . . . . 47 1.15.6.1 enable if-Funktionen . . . . . . . . . . . . . . . . . . . . 47 1.15.6.2 enable if-Funktions uberladen . . . . . . . . . . . . . . . 47 1.15.6.3 template class specializations . . . . . . . . . . . . . . . 48 1.16 R uckblick: typsichere Funktionsbenutzung . . . . . . . . . . . . . . . . . 49 1.17 Ausblick: C++2x eventuell mit eingeschr ankter Generizit at: Concepts (Prototypen von Klassen)
iii
1.18 1.19 1.20 1.21 1.22 1.23 1.24 1.25 1.26 1.27 2 Die 2.1 2.2 2.3 2.4 2.5 2.6
Generic Programming . . . . . . . . . . . . . . . . . . . . . . . . . . . . Generic Programming in ConceptC++ . . . . . . . . . . . . . . . . . . . Zielgerichtete Fehlermeldungen bei Nutzung einer C++-Standardbibliothek Concepts, concept maps, axioms . . . . . . . . . . . . . . . . . . . . . . . ConceptC++-Tutorial . . . . . . . . . . . . . . . . . . . . . . . . . . . . Generic Programming Techniques of the BOOST Libraries . . . . . . . . SFINAE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Assoziierte Typen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . POD-Typen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Checking Concepts without Concepts in C++ . . . . . . . . . . . . . . . Boost Concept Check Library (BCCL) Dierence of Draft C++ Cocepts and BCCL . . . . . . . . . . . . . . . . In der Boost-Bibliothek vordenierte (STL-)Konzepte . . . . . . . . . . . Ein Blick zur uck (2003..2008) und vorw arts (202x)? Usage-Pattern oder Creating Own Boost Concept Checking Classes . . . . . . . . . . . . . . Erstellung eines zugeh origen Archetypes . . . . . . . . . . . . . . . . . . Programmieren mit Konzepten . . . . . . . . . . . . . . . . . . . . . . .
53 54 mit Konzept 56 58 64 64 65 66 66
67 68 70 Pseudosignat 77 79 80
3 Trait-Klassen als Mittel der Absicherung vorhandener Eigenschaften aktueller generisch 3.1 Type Traits in D (Template Constraints) . . . . . . . . . . . . . . . . . 81 3.2 gcc Type-Traits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83 3.3 C++11 type traits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83 3.4 Boost Type-Traits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85 3.5 Boost Concept Traits Library . . . . . . . . . . . . . . . . . . . . . . . . 86 3.6 C++0x mit ersten Concepts: Numerics Library . . . . . . . . . . . . . . 86 3.7 Das ConceptWeb in ConceptC++ . . . . . . . . . . . . . . . . . . . . . . 88 3.8 Die (dokumentarisch genutzten) Konzepte der SGI STL Ubersicht . . 88 3.9 Glossar der generischen Programmierung . . . . . . . . . . . . . . . . . . 93 3.10 Verallgemeinerung von Algorithmen: Lifting . . . . . . . . . . . . . . . . 94 3.11 Modelle f ur Konzepte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94 3.12 Retroaktive Modellierung (r uckwirkend g ultig, mit Methoden-Namen- Umbenennung g 3.13 Checking Concepts without Concepts: Eigene Concept Traits . . . . . . . 97 3.14 Design of Concept Libraries for C++ (2011) . . . . . . . . . . . . . . . . 100 4 Metaprogrammierung 4.1 Metafunktionen . . . . . . . . . . . . . . . . . . 4.2 integral constant . . . . . . . . . . . . . . . . . 4.3 enum vs. static const vs. static constexpr . . . . 4.4 Typfunktionen . . . . . . . . . . . . . . . . . . . 4.5 Vor- und Nachteile der Metaprogrammierung . . 4.6 Fortgeschrittene Metaprogrammierung . . . . . 4.6.1 C++11 Compile-time rational arithmetic 4.6.2 Unrolled Loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103 103 104 105 107 108 109 109 111
iv
4.11
4.6.3 Expression templates . . . . . . . . . . . . . . . . . . . . . . . . . 114 Nachteile der Metaprogrammierung (Forts.) . . . . . . . . . . . . . . . . 116 Die BOOST Metaprogramming Library MPL . . . . . . . . . . . . . . . 116 Metaprogramme f ur die Manipulation von Typen in C++ . . . . . . . . 116 Spracherweiterung Maeinheiten . . . . . . . . . . . . . . . . . . . . . . . 118 4.10.1 Eine Softwarekatastrophe und ihr Einu auf neue Programmiersprachen118 4.10.2 DSLs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121 4.10.3 Ausug in die Domain des technische-wissenschaftlichen Rechnens: Units and Measure in F 4.10.4 SI-Einheitssystem . . . . . . . . . . . . . . . . . . . . . . . . . . . 122 4.10.5 Boost.Units . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122 4.10.6 Erweiterung des C++-Typsystems durch Units . . . . . . . . . . 132 4.10.7 Nachteile von DSLs . . . . . . . . . . . . . . . . . . . . . . . . . . 135 Literaturhinweise zum Metaprogrammieren . . . . . . . . . . . . . . . . . 135
5 Template template-Parameter, Policy-basiertes Klassendesign 137 5.1 Templates als Template-Parameter . . . . . . . . . . . . . . . . . . . . . 137 5.2 Policies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137 5.3 Entwurfsmuster Strategie . . . . . . . . . . . . . . . . . . . . . . . . . . . 140 5.4 Orthogonale Policy-Dimensionen . . . . . . . . . . . . . . . . . . . . . . 140 5.5 Policies (Fortsetzung) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140 5.6 Aspektorientiertes Programmiern in komplexen Unternehmensanwendungen141
Vorbemerkungen:
Literatur B. Stroustrup: Einf uhrung in die Programmierung mit C++, Pearson 2010, M unchen, Kapitel 19.3 . D. Vandervoorde, N. M. Josuttis: C++ Templates The Complede Guide, Pearson 2003, Boston Scott Meyers: Eective STL, Addison-Wesley 2001, Indianapolis Bj orn Karlsson: Beyond the C++ Standard Library An Introduction to Boost, Pearson 2006, Boston A. Alexandrescu: Modern C++ Design Generic Programming and Design Patterns Applied, Pearson 2001, Indianapolis Einordnung in Programmierparadigmen imperativ, objektbasiert, objektorientiert, funktional, generisch, ... Die Entwicklung der Aussagekraft der formalen generischen Parameter von einfallslosen Parameternamen wie class T1, class T2, ... vergleiche http://www.cplusplus.com/doc/tutorial/templates/ u ber semantisch inhaltsvolle Parameternamen wie typename InputIterator1, typename InputIterator2, typename NumericT, ... vergleiche http://www.iue.tuwien.ac.at/phd/heinzl/node32.html#SECTION010223000000000000000 hin zur Nennung der Requirements an die zur Instantiierung benutzbaren aktuellen Parameter wie T shall meet the requirements of CopyConstructible and CopyAssignable types (Seite 970 von http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3126.pdf) mit der Erl auterung:
http://www.heise.de/newsticker/meldung/C-11-einstimmig-als-Standard-angenommen-1322726.html C++11 ohne Concepts http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf beziehungsweise http://en.wikipedia.org/wiki/C%2B%2B11 TR1 - ein Zwischenstandard fu r die C++-Bibliothek TR1 http://en.wikipedia.org/wiki/Technical Report 2#Mathematical special functions Was h atten Concepts gebracht? http://en.wikipedia.org/wiki/Concepts (C%2B%2B) Ziele des Draft-Desings http://www.artima.com/cppsource/cpp0x.html TR2 call for proposals http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1810.html Typsicherheit ... bei generischen Konstrukten http://de.wikipedia.org/wiki/Typsicherheit http://en.wikipedia.org/wiki/Type safety Typsichere generische Typen in C++ uhrende Monster-Fehlermeldungen bei Instanziierung generischer C++-Konstrukte Irref at der C++ Template-Programmierung Hinweise zur Fehlermeldungsqualit Generics in Java C++11 Standard Library C++ standard library changes C++ Reference
1 Generische Programmierung
1.1 Was ist generische Programmierung?
http://pdfcast.org/pdf/the-java-generic-programming-system http://foldoc.org/generic+programming http://www.boost.org/community/generic programming.html http://en.wikipedia.org/wiki/Generic programming
#include < io st r ea m > using s t d : : co ut ; int main ( ) { int i = 5 ; int j = 6 ; co ut << i = << i << ; j = << j << s t d : : e n d l ; s t d : : swap ( i , j ) ; co ut << i = << i << ; j = << j << s t d : : e n d l ; int a [ 2 ] = { 2 , 3 } ; int b [ 2 ] = { 1 2 , 1 3 } ; co ut << a [ 0 ] << << co ut << b [ 0 ] << << s t d : : swap ( a , b ) ; co ut << a [ 0 ] << << co ut << b [ 0 ] << << }
an
den
generischen
Parameter
siehe
Die swappable.requirements ndet man in Aschnitt 20.2.2 des Drafts. Fassen Sie sie in eigenen Worten zusammen.
swap1.cpp
-o swap1
> ldd ./swap1 linux-vdso.so.1 => (0x00007fffe1b0d000) libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x00007fa6005e9000) libm.so.6 => /lib64/libm.so.6 (0x00007fa600392000)
10
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007fa60017c000) libc.so.6 => /lib64/libc.so.6 (0x00007fa5ffe1c000) /lib64/ld-linux-x86-64.so.2 (0x00007fa6008f3000) Beim Programmlauf werden nacheinander die shared object-Bibliotheken ge onet und n otige Teile in das auszuf uhrende Binary eingebunden:
> strace ./swap1 execve("./swap1", ["./swap1"], [/* 66 vars */]) = 0 brk(0) = 0x602000 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f17e3146000 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory) open("/etc/ld.so.cache", O_RDONLY) = 3 fstat(3, {st_mode=S_IFREG|0644, st_size=335735, ...}) = 0 mmap(NULL, 335735, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f17e30f4000 close(3) = 0 open("/usr/lib64/libstdc++.so.6", O_RDONLY) = 3 read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\260\305\5\0\0\0\0\0"..., 832) = 832 fstat(3, {st_mode=S_IFREG|0755, st_size=1003544, ...}) = 0 mmap(NULL, 3182936, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f17e2c1f000 fadvise64(3, 0, 3182936, POSIX_FADV_WILLNEED) = 0 mprotect(0x7f17e2d0b000, 2093056, PROT_NONE) = 0 mmap(0x7f17e2f0a000, 40960, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0xeb000) = 0x7f17e2f0a000 mmap(0x7f17e2f14000, 82264, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f17e2f14000 close(3) = 0 open("/lib64/libm.so.6", O_RDONLY) = 3 read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0>\0\0\0\0\0\0"..., 832) = 832 fstat(3, {st_mode=S_IFREG|0755, st_size=391908, ...}) = 0 mmap(NULL, 2449592, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f17e29c8000 fadvise64(3, 0, 2449592, POSIX_FADV_WILLNEED) = 0 mprotect(0x7f17e2a1e000, 2093056, PROT_NONE) = 0 mmap(0x7f17e2c1d000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x55000) = 0x7f17e2c1d000 close(3) = 0 open("/lib64/libgcc_s.so.1", O_RDONLY) = 3 read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0-\0\0\0\0\0\0"..., 832) = 832 fstat(3, {st_mode=S_IFREG|0755, st_size=88544, ...}) = 0 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f17e30f3000 mmap(NULL, 2184184, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f17e27b2000 fadvise64(3, 0, 2184184, POSIX_FADV_WILLNEED) = 0 mprotect(0x7f17e27c7000, 2093056, PROT_NONE) = 0 mmap(0x7f17e29c6000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x14000) = 0x7f17e29c6000 close(3) = 0 open("/lib64/libc.so.6", O_RDONLY) = 3 read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\220\354\1\0\0\0\0\0"..., 832) = 832 fstat(3, {st_mode=S_IFREG|0755, st_size=1670469, ...}) = 0 mmap(NULL, 3537800, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f17e2452000 fadvise64(3, 0, 3537800, POSIX_FADV_WILLNEED) = 0 mprotect(0x7f17e25a8000, 2097152, PROT_NONE) = 0 mmap(0x7f17e27a8000, 20480, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x156000) = 0x7f17e27a8000 mmap(0x7f17e27ad000, 19336, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f17e27ad000 close(3) = 0 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f17e30f2000 mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f17e30f0000 arch_prctl(ARCH_SET_FS, 0x7f17e30f0720) = 0 mprotect(0x7f17e27a8000, 16384, PROT_READ) = 0 mprotect(0x7f17e29c6000, 4096, PROT_READ) = 0 mprotect(0x7f17e2c1d000, 4096, PROT_READ) = 0 mprotect(0x7f17e2f0a000, 32768, PROT_READ) = 0 mprotect(0x600000, 4096, PROT_READ) = 0 mprotect(0x7f17e3147000, 4096, PROT_READ) = 0 munmap(0x7f17e30f4000, 335735) = 0 fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 2), ...}) = 0 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f17e3145000 write(1, "1 5\n", 41 5
11
) = 4 write(1, "5 1\n", 45 1 ) = 4 write(1, "3.1415 15.1055\n", 153.1415 15.1055 ) = 15 write(1, "15.1055 3.1415\n", 1515.1055 3.1415 ) = 15 exit_group(0) = ?
Neben gcc, g++, as, ld, gprof und gdb/ddd sind die folgenden Tools von Interesse. Die GNU-Binutils: nm objdump objcopy readelf strip size c++lt ar ranlib > file ./swap1 ./swap1: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.15, not stripped > nm ./swap1 0000000000600e20 d _DYNAMIC 0000000000600fe8 d _GLOBAL_OFFSET_TABLE_ 0000000000400a75 t _GLOBAL__I_main 0000000000400bd8 R _IO_stdin_used w _Jv_RegisterClasses 0000000000400a35 t _Z41__static_initialization_and_destruction_0ii 0000000000400ab6 W _Z4swapIdEvRT_S1_ 0000000000400a8a W _Z4swapIiEvRT_S1_ U _ZNSolsEPFRSoS_E@@GLIBCXX_3.4 U _ZNSolsEd@@GLIBCXX_3.4 U _ZNSolsEi@@GLIBCXX_3.4 U _ZNSt8ios_base4InitC1Ev@@GLIBCXX_3.4 U _ZNSt8ios_base4InitD1Ev@@GLIBCXX_3.4 0000000000601060 B _ZSt4cout@@GLIBCXX_3.4
12
0000000000601180 0000000000600e00 0000000000600df0 0000000000600e10 0000000000600e08 0000000000400d40 0000000000600e18 0000000000600e18 0000000000601060 0000000000601050 0000000000400b90 0000000000400850 0000000000601058
0000000000600dec 0000000000600dec 0000000000400af0 0000000000400b00 0000000000601060 0000000000601188 0000000000400bc8 0000000000400730 0000000000400800 000000000040082c 0000000000601170 0000000000601050 0000000000601178 00000000004008c0 00000000004008e4
U b U d d D d r d d A U D t t D w U d d T T U A A T T T t b W b t T
_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_@@GLIBCXX_3. _ZStL8__ioinit _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@@GLIBCXX_3.4 __CTOR_END__ __CTOR_LIST__ __DTOR_END__ __DTOR_LIST__ __FRAME_END__ __JCR_END__ __JCR_LIST__ __bss_start __cxa_atexit@@GLIBC_2.2.5 __data_start __do_global_ctors_aux __do_global_dtors_aux __dso_handle __gmon_start__ __gxx_personality_v0@@CXXABI_1.3 __init_array_end __init_array_start __libc_csu_fini __libc_csu_init __libc_start_main@@GLIBC_2.2.5 _edata _end _fini _init _start call_gmon_start completed.7424 data_start dtor_idx.7426 frame_dummy main
... und mit demangled Symbolen: nm ./swap1 | c++filt 0000000000600e20 d _DYNAMIC 0000000000600fe8 d _GLOBAL_OFFSET_TABLE_ 0000000000400a75 t global constructors keyed to main 0000000000400bd8 R _IO_stdin_used w _Jv_RegisterClasses 0000000000400a35 t __static_initialization_and_destruction_0(int, int)
13
0000000000400ab6 W void swap<double>(double&, double&) 0000000000400a8a W void swap<int>(int&, int&) U std::basic_ostream<char, std::char_traits<char> U std::basic_ostream<char, std::char_traits<char> U std::basic_ostream<char, std::char_traits<char> U std::ios_base::Init::Init()@@GLIBCXX_3.4 U std::ios_base::Init::~Init()@@GLIBCXX_3.4 0000000000601060 B std::cout@@GLIBCXX_3.4 U std::basic_ostream<char, std::char_traits<char> 0000000000601180 b std::__ioinit U std::basic_ostream<char, std::char_traits<char> 0000000000600e00 d __CTOR_END__ 0000000000600df0 d __CTOR_LIST__ 0000000000600e10 D __DTOR_END__ 0000000000600e08 d __DTOR_LIST__ 0000000000400d40 r __FRAME_END__ 0000000000600e18 d __JCR_END__ 0000000000600e18 d __JCR_LIST__ 0000000000601060 A __bss_start U __cxa_atexit@@GLIBC_2.2.5 0000000000601050 D __data_start 0000000000400b90 t __do_global_ctors_aux 0000000000400850 t __do_global_dtors_aux 0000000000601058 D __dso_handle w __gmon_start__ U __gxx_personality_v0@@CXXABI_1.3 0000000000600dec d __init_array_end 0000000000600dec d __init_array_start 0000000000400af0 T __libc_csu_fini 0000000000400b00 T __libc_csu_init U __libc_start_main@@GLIBC_2.2.5 0000000000601060 A _edata 0000000000601188 A _end 0000000000400bc8 T _fini 0000000000400730 T _init 0000000000400800 T _start 000000000040082c t call_gmon_start 0000000000601170 b completed.7424 0000000000601050 W data_start 0000000000601178 b dtor_idx.7426 00000000004008c0 t frame_dummy 00000000004008e4 T main
>& std::endl<c
>& std::operat
14
> c++filt -n _Z4swapIiEvRT_S1_ void swap<int>(int&, int&) Vergleiche: C++ name mangling names in object les name mangling in Java Getting the best from g++
15
> objdump -x swap1 | c++filt swap1: file format elf64-x86-64 swap1 architecture: i386:x86-64, flags 0x00000112: EXEC_P, HAS_SYMS, D_PAGED start address 0x00000000004007e0 Program Header: PHDR off 0x0000000000000040 vaddr 0x0000000000400040 paddr 0x0000000000400040 align 2**3 filesz 0x00000000000001f8 memsz 0x00000000000001f8 flags r-x INTERP off 0x0000000000000238 vaddr 0x0000000000400238 paddr 0x0000000000400238 align 2**0 filesz 0x000000000000001c memsz 0x000000000000001c flags r-... Dynamic Section: NEEDED libstdc++.so.6 NEEDED libm.so.6 NEEDED libgcc_s.so.1 NEEDED libc.so.6 INIT 0x0000000000400720 FINI 0x0000000000400ba8 ... Version References: required from libc.so.6: 0x09691a75 0x00 03 GLIBC_2.2.5 required from libstdc++.so.6: 0x08922974 0x00 02 GLIBCXX_3.4 Sections: Idx Name Size VMA LMA File off Algn 0 .interp 0000001c 0000000000400238 0000000000400238 00000238 2**0 CONTENTS, ALLOC, LOAD, READONLY, DATA 1 .note.ABI-tag 00000020 0000000000400254 0000000000400254 00000254 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 2 .note.SuSE 00000018 0000000000400274 0000000000400274 00000274 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 3 .note.gnu.build-id 00000024 000000000040028c 000000000040028c 0000028c 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 4 .hash 00000048 00000000004002b0 00000000004002b0 000002b0 2**3 CONTENTS, ALLOC, LOAD, READONLY, DATA 5 .gnu.hash 00000030 00000000004002f8 00000000004002f8 000002f8 2**3 CONTENTS, ALLOC, LOAD, READONLY, DATA 6 .dynsym 00000138 0000000000400328 0000000000400328 00000328 2**3 CONTENTS, ALLOC, LOAD, READONLY, DATA 7 .dynstr 0000015e 0000000000400460 0000000000400460 00000460 2**0 CONTENTS, ALLOC, LOAD, READONLY, DATA 8 .gnu.version 0000001a 00000000004005be 00000000004005be 000005be 2**1 CONTENTS, ALLOC, LOAD, READONLY, DATA 9 .gnu.version_r 00000040 00000000004005d8 00000000004005d8 000005d8 2**3 CONTENTS, ALLOC, LOAD, READONLY, DATA 10 .rela.dyn 00000030 0000000000400618 0000000000400618 00000618 2**3 CONTENTS, ALLOC, LOAD, READONLY, DATA 11 .rela.plt 000000d8 0000000000400648 0000000000400648 00000648 2**3 CONTENTS, ALLOC, LOAD, READONLY, DATA 12 .init 00000018 0000000000400720 0000000000400720 00000720 2**2 CONTENTS, ALLOC, LOAD, READONLY, CODE 13 .plt 000000a0 0000000000400738 0000000000400738 00000738 2**2 CONTENTS, ALLOC, LOAD, READONLY, CODE 14 .text 000003c8 00000000004007e0 00000000004007e0 000007e0 2**4 CONTENTS, ALLOC, LOAD, READONLY, CODE 15 .fini 0000000e 0000000000400ba8 0000000000400ba8 00000ba8 2**2 CONTENTS, ALLOC, LOAD, READONLY, CODE 16 .rodata 00000006 0000000000400bb8 0000000000400bb8 00000bb8 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 17 .eh_frame_hdr 00000044 0000000000400bc0 0000000000400bc0 00000bc0 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 18 .eh_frame 00000104 0000000000400c08 0000000000400c08 00000c08 2**3
16
19 .ctors 20 .dtors ... 25 .data 26 .bss ... SYMBOL TABLE: 0000000000400238 0000000000400254 0000000000400274 000000000040028c 00000000004002b0 00000000004002f8 0000000000400328 0000000000400460 00000000004005be 00000000004005d8 0000000000400618 0000000000400648 0000000000400720 0000000000400738 00000000004007e0 0000000000400ba8 0000000000400bb8 ... 0000000000400a96 ... 0000000000400a6a 0000000000601058 00000000004008c4 0000000000400720
ALLOC, LOAD, READONLY, DATA 0000000000600de0 0000000000600de0 ALLOC, LOAD, DATA 0000000000600df8 0000000000600df8 ALLOC, LOAD, DATA
00000de0 00000df8
2**3 2**3
00000010 0000000000601048 0000000000601048 CONTENTS, ALLOC, LOAD, DATA 00000128 0000000000601060 0000000000601060 ALLOC
00001048 00001058
2**3 2**5
l l l l l l l l l l l l l l l l l w w g g g
d d d d d d d d d d d d d d d d d
.interp 0000000000000000 .note.ABI-tag 0000000000000000 .note.SuSE 0000000000000000 .note.gnu.build-id 0000000000000000 .hash 0000000000000000 .hash .gnu.hash 0000000000000000 .dynsym 0000000000000000 .dynstr 0000000000000000 .gnu.version 0000000000000000 .gnu.version_r 0000000000000000 .rela.dyn 0000000000000000 .rela.plt 0000000000000000 .init 0000000000000000 .init .plt 0000000000000000 .plt .text 0000000000000000 .text .fini 0000000000000000 .fini .rodata 0000000000000000 0000000000000032 000000000000002c 0000000000000000 0000000000000151 0000000000000000
.interp .note.ABI-tag .note.SuSE .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt
.rodata
> objdump -t swap1 | c++filt swap1: file format elf64-x86-64 SYMBOL TABLE: 0000000000400238 l d .interp 0000000000000000 0000000000400254 l d .note.ABI-tag 0000000000000000 0000000000400274 l d .note.SuSE 0000000000000000 000000000040028c l d .note.gnu.build-id 0000000000000000 00000000004002b0 l d .hash 0000000000000000 .hash 00000000004002f8 l d .gnu.hash 0000000000000000 0000000000400328 l d .dynsym 0000000000000000 0000000000400460 l d .dynstr 0000000000000000 00000000004005be l d .gnu.version 0000000000000000 00000000004005d8 l d .gnu.version_r 0000000000000000 0000000000400618 l d .rela.dyn 0000000000000000 0000000000400648 l d .rela.plt 0000000000000000 0000000000400720 l d .init 0000000000000000 .init 0000000000400738 l d .plt 0000000000000000 .plt 00000000004007e0 l d .text 0000000000000000 .text 0000000000400ba8 l d .fini 0000000000000000 .fini 0000000000400bb8 l d .rodata 0000000000000000 0000000000400bc0 l d .eh_frame_hdr 0000000000000000 0000000000400c08 l d .eh_frame 0000000000000000 0000000000600de0 l d .ctors 0000000000000000 .ctors 0000000000600df8 l d .dtors 0000000000000000 .dtors 0000000000600e08 l d .jcr 0000000000000000 .jcr 0000000000600e10 l d .dynamic 0000000000000000 0000000000600fe0 l d .got 0000000000000000 .got 0000000000600fe8 l d .got.plt 0000000000000000 0000000000601048 l d .data 0000000000000000 .data
.interp .note.ABI-tag .note.SuSE .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt
.dynamic .got.plt
17
0000000000601060 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 000000000040080c 0000000000000000 0000000000600de0 0000000000600df8 0000000000600e08 0000000000400830 0000000000601170 0000000000601178 00000000004008a0 0000000000000000 0000000000600df0 0000000000400d08 0000000000600e08 0000000000400b70 0000000000000000 0000000000000000 0000000000601180 0000000000400a15 0000000000400a55 0000000000000000 0000000000600fe8 0000000000600ddc 0000000000600ddc 0000000000600e10 0000000000601048 0000000000000000 0000000000000000 0000000000400b60 00000000004007e0 0000000000000000 0000000000000000 0000000000400ba8 0000000000000000 0000000000000000 0000000000000000 0000000000400798 0000000000000000 0000000000400bb8 0000000000601048 0000000000400a96 0000000000601060 0000000000601050 0000000000600e00 0000000000400ad0 0000000000601058 0000000000601188 0000000000000000 00000000004007c8 0000000000400a6a 0000000000601058 00000000004008c4 0000000000400720
l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l l w
d d d d d d d d d d d d df df F df O O O F O O F df O O O F df df O F F df O
O F F F F
g g w w g
g g w g g g g g g
F F F F F F O F O O O F
w g g g
F F F F F
.bss 0000000000000000 .bss .comment.SUSE.OPTs 0000000000000000 .comment.SUSE.OPTs .comment 0000000000000000 .comment .debug_aranges 0000000000000000 .debug_aranges .debug_pubnames 0000000000000000 .debug_pubnames .debug_info 0000000000000000 .debug_info .debug_abbrev 0000000000000000 .debug_abbrev .debug_line 0000000000000000 .debug_line .debug_str 0000000000000000 .debug_str .debug_loc 0000000000000000 .debug_loc .debug_pubtypes 0000000000000000 .debug_pubtypes .debug_ranges 0000000000000000 .debug_ranges *ABS* 0000000000000000 init.c *ABS* 0000000000000000 initfini.c .text 0000000000000000 call_gmon_start *ABS* 0000000000000000 crtstuff.c .ctors 0000000000000000 __CTOR_LIST__ .dtors 0000000000000000 __DTOR_LIST__ .jcr 0000000000000000 __JCR_LIST__ .text 0000000000000000 __do_global_dtors_aux .bss 0000000000000001 completed.5939 .bss 0000000000000008 dtor_idx.5941 .text 0000000000000000 frame_dummy *ABS* 0000000000000000 crtstuff.c .ctors 0000000000000000 __CTOR_END__ .eh_frame 0000000000000000 __FRAME_END__ .jcr 0000000000000000 __JCR_END__ .text 0000000000000000 __do_global_ctors_aux *ABS* 0000000000000000 initfini.c *ABS* 0000000000000000 swap1.cpp .bss 0000000000000001 std::__ioinit .text 0000000000000040 __static_initialization_and_destruction_0(int, int) .text 0000000000000015 global constructors keyed to main *ABS* 0000000000000000 elf-init.c .got.plt 0000000000000000 .hidden _GLOBAL_OFFSET_TABLE_ .ctors 0000000000000000 .hidden __init_array_end .ctors 0000000000000000 .hidden __init_array_start .dynamic 0000000000000000 .hidden _DYNAMIC .data 0000000000000000 data_start *UND* 0000000000000000 std::basic_ostream<char, std::char_traits<char> >::opera *UND* 0000000000000000 std::basic_ostream<char, std::char_traits<char> >::opera .text 0000000000000002 __libc_csu_fini .text 0000000000000000 _start *UND* 0000000000000000 __gmon_start__ *UND* 0000000000000000 _Jv_RegisterClasses .fini 0000000000000000 _fini *UND* 0000000000000000 std::ios_base::Init::Init()@@GLIBCXX_3.4 *UND* 0000000000000000 __libc_start_main@@GLIBC_2.2.5 *UND* 0000000000000000 __cxa_atexit@@GLIBC_2.2.5 *UND* 0000000000000000 std::ios_base::Init::~Init()@@GLIBCXX_3.4 *UND* 0000000000000000 std::basic_ostream<char, std::char_traits<char> >& std:: .rodata 0000000000000004 _IO_stdin_used .data 0000000000000000 __data_start .text 0000000000000032 void swap<double>(double&, double&) .bss 0000000000000110 std::cout@@GLIBCXX_3.4 .data 0000000000000000 .hidden __dso_handle .dtors 0000000000000000 .hidden __DTOR_END__ .text 0000000000000089 __libc_csu_init *ABS* 0000000000000000 __bss_start *ABS* 0000000000000000 _end *UND* 0000000000000000 std::basic_ostream<char, std::char_traits<char> >::opera *UND* 0000000000000000 std::basic_ostream<char, std::char_traits<char> >& std:: .text 000000000000002c void swap<int>(int&, int&) *ABS* 0000000000000000 _edata .text 0000000000000151 main .init 0000000000000000 _init
18
> readelf -s swap1 | c++filt Symbol table .dynsym contains 13 entries: Num: Value Size Type Bind 0: 0000000000000000 0 NOTYPE LOCAL 1: 0000000000000000 0 FUNC GLOBAL 2: 0000000000000000 0 FUNC GLOBAL 3: 0000000000000000 0 NOTYPE WEAK 4: 0000000000000000 0 NOTYPE WEAK 5: 0000000000000000 0 FUNC GLOBAL 6: 0000000000000000 0 FUNC GLOBAL 7: 0000000000000000 0 FUNC GLOBAL 8: 0000000000000000 0 FUNC GLOBAL 9: 0000000000000000 0 FUNC GLOBAL 10: 00000000004007c8 0 FUNC GLOBAL 11: 0000000000400798 0 FUNC GLOBAL 12: 0000000000601060 272 OBJECT GLOBAL Symbol table .symtab contains 93 entries: Num: Value Size Type Bind 0: 0000000000000000 0 NOTYPE LOCAL 1: 0000000000400238 0 SECTION LOCAL 2: 0000000000400254 0 SECTION LOCAL 3: 0000000000400274 0 SECTION LOCAL 4: 000000000040028c 0 SECTION LOCAL 5: 00000000004002b0 0 SECTION LOCAL 6: 00000000004002f8 0 SECTION LOCAL 7: 0000000000400328 0 SECTION LOCAL 8: 0000000000400460 0 SECTION LOCAL 9: 00000000004005be 0 SECTION LOCAL 10: 00000000004005d8 0 SECTION LOCAL 11: 0000000000400618 0 SECTION LOCAL 12: 0000000000400648 0 SECTION LOCAL 13: 0000000000400720 0 SECTION LOCAL 14: 0000000000400738 0 SECTION LOCAL 15: 00000000004007e0 0 SECTION LOCAL 16: 0000000000400ba8 0 SECTION LOCAL 17: 0000000000400bb8 0 SECTION LOCAL 18: 0000000000400bc0 0 SECTION LOCAL 19: 0000000000400c08 0 SECTION LOCAL 20: 0000000000600de0 0 SECTION LOCAL 21: 0000000000600df8 0 SECTION LOCAL 22: 0000000000600e08 0 SECTION LOCAL 23: 0000000000600e10 0 SECTION LOCAL 24: 0000000000600fe0 0 SECTION LOCAL 25: 0000000000600fe8 0 SECTION LOCAL 26: 0000000000601048 0 SECTION LOCAL 27: 0000000000601060 0 SECTION LOCAL 28: 0000000000000000 0 SECTION LOCAL 29: 0000000000000000 0 SECTION LOCAL 30: 0000000000000000 0 SECTION LOCAL 31: 0000000000000000 0 SECTION LOCAL 32: 0000000000000000 0 SECTION LOCAL 33: 0000000000000000 0 SECTION LOCAL 34: 0000000000000000 0 SECTION LOCAL 35: 0000000000000000 0 SECTION LOCAL 36: 0000000000000000 0 SECTION LOCAL 37: 0000000000000000 0 SECTION LOCAL 38: 0000000000000000 0 SECTION LOCAL 39: 0000000000000000 0 FILE LOCAL 40: 0000000000000000 0 FILE LOCAL 41: 000000000040080c 0 FUNC LOCAL 42: 0000000000000000 0 FILE LOCAL 43: 0000000000600de0 0 OBJECT LOCAL 44: 0000000000600df8 0 OBJECT LOCAL 45: 0000000000600e08 0 OBJECT LOCAL 46: 0000000000400830 0 FUNC LOCAL 47: 0000000000601170 1 OBJECT LOCAL 48: 0000000000601178 8 OBJECT LOCAL 49: 00000000004008a0 0 FUNC LOCAL 50: 0000000000000000 0 FILE LOCAL 51: 0000000000600df0 0 OBJECT LOCAL 52: 0000000000400d08 0 OBJECT LOCAL 53: 0000000000600e08 0 OBJECT LOCAL 54: 0000000000400b70 0 FUNC LOCAL 55: 0000000000000000 0 FILE LOCAL 56: 0000000000000000 0 FILE LOCAL 57: 0000000000601180 1 OBJECT LOCAL 58: 0000000000400a15 64 FUNC LOCAL 59: 0000000000400a55 21 FUNC LOCAL 60: 0000000000000000 0 FILE LOCAL 61: 0000000000600fe8 0 OBJECT LOCAL 62: 0000000000600ddc 0 NOTYPE LOCAL 63: 0000000000600ddc 0 NOTYPE LOCAL 64: 0000000000600e10 0 OBJECT LOCAL 65: 0000000000601048 0 NOTYPE WEAK 66: 0000000000000000 0 FUNC GLOBAL 67: 0000000000000000 0 FUNC GLOBAL 68: 0000000000400b60 2 FUNC GLOBAL 69: 00000000004007e0 0 FUNC GLOBAL
Vis DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT
Ndx UND UND UND UND UND UND UND UND UND UND UND UND 27
Name std::basic_ostream<char, std::char_traits<char> >::operator<<(double)@GLIBCXX_3.4 (2) std::basic_ostream<char, std::char_traits<char> >::operator<<(int)@GLIBCXX_3.4 (2) __gmon_start__ _Jv_RegisterClasses std::ios_base::Init::Init()@GLIBCXX_3.4 (2) __libc_start_main@GLIBC_2.2.5 (3) __cxa_atexit@GLIBC_2.2.5 (3) _ZStlsISt11char_traitsIcE@GLIBCXX_3.4 (2) std::basic_ostream<char, std::char_traits<char> >::operator<<(std::basic_ostream<char, std::char_traits<char> >& _ZSt4endlIcSt11char_trait@GLIBCXX_3.4 (2) std::ios_base::Init::~Init()@GLIBCXX_3.4 (2) std::cout@GLIBCXX_3.4 (2)
Vis DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT HIDDEN HIDDEN HIDDEN HIDDEN DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT
Ndx Name UND 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 ABS init.c ABS initfini.c 15 call_gmon_start ABS crtstuff.c 20 __CTOR_LIST__ 21 __DTOR_LIST__ 22 __JCR_LIST__ 15 __do_global_dtors_aux 27 completed.5939 27 dtor_idx.5941 15 frame_dummy ABS crtstuff.c 20 __CTOR_END__ 19 __FRAME_END__ 22 __JCR_END__ 15 __do_global_ctors_aux ABS initfini.c ABS swap1.cpp 27 std::__ioinit 15 _Z41__static_initializati 15 global constructors keyed to main ABS elf-init.c 25 _GLOBAL_OFFSET_TABLE_ 20 __init_array_end 20 __init_array_start 23 _DYNAMIC 26 data_start UND std::basic_ostream<char, std::char_traits<char> >::operator<<(double)@@GLIBCXX_3.4 UND std::basic_ostream<char, std::char_traits<char> >::operator<<(int)@@GLIBCXX_3.4 15 __libc_csu_fini 15 _start
19
70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92:
0000000000000000 0000000000000000 0000000000400ba8 0000000000000000 0000000000000000 0000000000000000 0000000000400798 0000000000000000 0000000000400bb8 0000000000601048 0000000000400a96 0000000000601060 0000000000601050 0000000000600e00 0000000000400ad0 0000000000601058 0000000000601188 0000000000000000 00000000004007c8 0000000000400a6a 0000000000601058 00000000004008c4 0000000000400720
NOTYPE NOTYPE FUNC FUNC FUNC FUNC FUNC FUNC OBJECT NOTYPE FUNC OBJECT OBJECT OBJECT FUNC NOTYPE NOTYPE FUNC FUNC FUNC NOTYPE FUNC FUNC
WEAK WEAK GLOBAL GLOBAL GLOBAL GLOBAL GLOBAL GLOBAL GLOBAL GLOBAL WEAK GLOBAL GLOBAL GLOBAL GLOBAL GLOBAL GLOBAL GLOBAL GLOBAL WEAK GLOBAL GLOBAL GLOBAL
DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT HIDDEN HIDDEN DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT DEFAULT
UND __gmon_start__ UND _Jv_RegisterClasses 16 _fini UND std::ios_base::Init::Init()@@ UND __libc_start_main@@GLIBC_ UND __cxa_atexit@@GLIBC_2.2.5 UND std::ios_base::Init::~Init()@@ UND _ZStlsISt11char_traitsIcE 17 _IO_stdin_used 26 __data_start 15 void swap<double>(double&, double&) 27 std::cout@@GLIBCXX_3.4 26 __dso_handle 21 __DTOR_END__ 15 __libc_csu_init ABS __bss_start ABS _end UND std::basic_ostream<char, std::char_traits<char> >::operator<<(std::basic_ostream<char, std::char_t UND _ZSt4endlIcSt11char_trait 15 void swap<int>(int&, int&) ABS _edata 15 main 13 _init
Die Sektionstypen von Objektdateien: test, data und bss Hinweis zu verf ugbaren Softwareentwicklungssystemen: ur Linux GNU g++ f ur Windows cygwin f ur Windows Visual Studio 2010 f
20
> cat swap1.cpp #include < io st r ea m > template <typename T> / Requirements : T muss e i n e n K o p i e r k o n s t r u k t o r haben , T muss e i n e n Z u w e i s u n g s o p e r a t o r zu T haben . / void swap (T& a , T& b ) { T old a (a) ; a = b; b = old a ; } int main ( ) { int k ( 1 ) ; int l ( 5 ) ; s t d : : co ut << k << << l << s t d : : e n d l ; swap ( k , l ) ; s t d : : co ut << k << << l << s t d : : e n d l ; double d1 ( 3 . 1 4 1 5 ) ; double d2 ( 1 5 . 1 0 5 5 ) ; s t d : : co ut << d1 << << d2 << s t d : : e n d l ; swap ( d1 , d2 ) ; s t d : : co ut << d1 << << d2 << s t d : : e n d l ; } > make CXXFLAGS=-g swap1
21
g++ -g swap1.cpp -o swap1 > nm swap1 | grep swap | c++filt 0000000000400a96 W void swap<double>(double&, double&) 0000000000400a6a W void swap<int>(int&, int&) > g++ -c swap1.cpp > ls -al swap1.o -rw-r--r-- 1 user1 users 4464 > ar rc libswap.a swap1.o > ls -al libswap.a -rw-r--r-- 1 user1 users 4650
> nm libswap.a | c++filt 0000000000000000 W void swap<double>(double&, double&) 0000000000000000 W void swap<int>(int&, int&) U std::basic_ostream<char, std::char_traits<char> >::operator<<( U std::basic_ostream<char, std::char_traits<char> >::operator<<( 0000000000000000 T main oder ein vollst andiges Beispiel: > cat person.h / p e rs o n . h / c l a s s Person { public : Person ( ) { } ; Person ( ) { } ; void speak ( const char s e n t e n c e ) ; }; > cat person.cpp #include p e r s o n . h #include < io st r ea m > void Person : : speak ( const char s e n t e n c e ) { s t d : : co ut << s e n t e n c e << s t d : : e n d l ; }
22
> cat main.cpp / main . cpp / #include p e r s o n . h #include < io st r ea m > int main ( ) { Person p e r s o n ; p e r s o n . speak ( H e l l o world ! ) ; return 0 ; } > > > > > g++ -c person.cpp g++ -c main.cpp ar rc libperson.a person.o g++ -o main main.o -L. -lperson ldd main linux-vdso.so.1 => (0x00007fffdfbff000) libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x00007f1f48ef2000) libm.so.6 => /lib64/libm.so.6 (0x00007f1f48c9b000) libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f1f48a85000) libc.so.6 => /lib64/libc.so.6 (0x00007f1f48725000) /lib64/ld-linux-x86-64.so.2 (0x00007f1f491fc000)
23
24
25
urs 1.6 STL-Templatequellen unter SuSE-Linux f zeilenweise Debuggen auch innerhalb der STL-Routinen
26
geomMittel2 ( 3 . 0 , 3 0 0 . 0 ) << e n d l ; geomMittel2 ( 3 , 3 0 0 . 0 ) << e n d l ; geomMittel2 ( 3 , 3 0 0 . 0 ) << e n d l ; geomMittel2 ( 3 , 3 0 0 ) << e n d l ; geomMittel2 ( 3 . 0 , c ) << e n d l ; geomMittel2 ( 3 . 0 , c ) << e n d l ;
27
Nach einer verbesserten Bezeichnerwahl: #include < io st r ea m > #include <cmath> #include < l i m i t s > using namespace s t d ; template <typename A r i t h m e t i c L i k e 1 , typename A r i t h m e t i c L i k e 2 > double geomMittel2 ( const A r i t h m e t i c L i k e 1& a , const A r i t h m e t i c L i k e 2& b ) { return s q r t ( abs ( a b ) ) ; } int main ( ) { co ut << co ut << co ut << co ut << co ut << co ut <<
geomMittel2 ( 3 . 0 , 3 0 0 . 0 ) << e n d l ; geomMittel2 ( 3 , 3 0 0 . 0 ) << e n d l ; geomMittel2 ( 3 , 3 0 0 . 0 ) << e n d l ; geomMittel2 ( 3 , 3 0 0 ) << e n d l ; geomMittel2 ( 3 . 0 , c ) << e n d l ; geomMittel2 ( 3 . 0 , c ) << e n d l ;
28
using namespace s t d ; BOOST STATIC ASSERT( s t d : : n u m e r i c l i m i t s <int > : : d i g i t s >= 3 2 ) ; template <typename A r i t h m e t i c L i k e 1 , typename A r i t h m e t i c L i k e 2 > double geomMittel2 ( const A r i t h m e t i c L i k e 1& a , const A r i t h m e t i c L i k e 2& b ) { BOOST STATIC ASSERT ( : : b o o s t : : i s a r i t h m e t i c <A r i t h m e t i c L i k e 1 > : : value ) ; BOOST STATIC ASSERT ( : : b o o s t : : i s a r i t h m e t i c <A r i t h m e t i c L i k e 2 > : : value ) ; return s q r t ( abs ( a b ) ) ; } int main ( ) { co ut << co ut << co ut << co ut << co ut << co ut <<
geomMittel2 ( 3 . 0 , 3 0 0 . 0 ) << e n d l ; geomMittel2 ( 3 , 3 0 0 . 0 ) << e n d l ; geomMittel2 ( 3 , 3 0 0 . 0 ) << e n d l ; geomMittel2 ( 3 , 3 0 0 ) << e n d l ; geomMittel2 ( 3 . 0 , c ) << e n d l ; geomMittel2 ( 3 . 0 , c ) << e n d l ;
return 0 ; }
geomMittel2.cpp:9:1: Fehler: Ung ultige Anwendung von sizeof auf unvollst andigen Typen boost::STATIC_ASSERTION_FAILURE<false> geomMittel2.cpp: In Funktion double geomMittel2(const ArithmeticLike1&, const ArithmeticLike2&) [with ArithmeticLike1 = double, ArithmeticLike2 = char [2]] : geomMittel2.cpp:28:33: instantiated from here geomMittel2.cpp:15:1: Fehler: Ung ultige Anwendung von sizeof auf unvollst andigen Typen boost::STATIC_ASSERTION_FAILURE<false> geomMittel2.cpp:17:25: Fehler: ung ultige Operanden der Typen const double und const char [2] f ur bin ares operator*
29
using namespace s t d ; s t a t i c a s s e r t ( s t d : : n u m e r i c l i m i t s <int > : : d i g i t s >= 3 2 , i n t not enough d i g i t s ) ; template <typename A r i t h m e t i c L i k e 1 , typename A r i t h m e t i c L i k e 2 > double geomMittel2 ( const A r i t h m e t i c L i k e 1& a , const A r i t h m e t i c L i k e 2& b ) { s t a t i c a s s e r t ( : : b o o s t : : i s a r i t h m e t i c <A r i t h m e t i c L i k e 1 > : : va lue , A r i t h m e t i c L i k e 1 i s not a r i t h m e t i c ) ; s t a t i c a s s e r t ( : : b o o s t : : i s a r i t h m e t i c <A r i t h m e t i c L i k e 2 > : : va lue , A r i t h m e t i c L i k e 2 i s not a r i t h m e t i c ) ; return s q r t ( abs ( a b ) ) ; } // u e b e r s e t z e mit s t d=c++0x // o d e r make CXXFLAGS= s t d=c++0x . . . int main ( ) { co ut << co ut << co ut << co ut << co ut << co ut <<
geomMittel2 ( 3 . 0 , 3 0 0 . 0 ) << e n d l ; geomMittel2 ( 3 , 3 0 0 . 0 ) << e n d l ; geomMittel2 ( 3 , 3 0 0 . 0 ) << e n d l ; geomMittel2 ( 3 , 3 0 0 ) << e n d l ; geomMittel2 ( 3 . 0 , c ) << e n d l ; geomMittel2 ( 3 . 0 , c ) << e n d l ;
return 0 ; }
geomMittel-sa2.cpp: In Funktion double geomMittel2(const ArithmeticLike1&, const ArithmeticLike2&) [with ArithmeticLike1 = double, ArithmeticLike2 = char geomMittel-sa2.cpp:29:33: instantiated from here geomMittel-sa2.cpp:14:1: Fehler: statische Behauptung gescheitert: "ArithmeticLike2 is not arithmetic" geomMittel-sa2.cpp:16:25: Fehler: ung ultige Operanden der Typen const double und const char [2] f ur bin ares operator* make: *** [geomMittel-sa2] Fehler 1
30
1.8
testmm . cpp : 3 0 : e r r o r : cannot c o n v e r t s t d : : R b t r e e i t e r a t o r < s t d : : p a i r <const s t d : : b a s i c s t r i n g <char , s t d : : c h a r t r a i t s < char > , s t d : : a l l o c a t o r <char> > , Widget> > t o int i n initialization testmm . cpp : 3 6 : e r r o r : no matching f u n c t i o n for c a l l t o s t d : : multimap<s t d : : b a s i c s t r i n g <char , s t d : : c h a r t r a i t s <char > , s t d : : a l l o c a t o r <char> > , Widget , s t d : : l e s s <s t d : : b a s i c s t r i n g < char , s t d : : c h a r t r a i t s <char > , s t d : : a l l o c a t o r <char> > > , s t d : : a l l o c a t o r <s t d : : p a i r <const s t d : : b a s i c s t r i n g <char , s t d : : c h a r t r a i t s <char > , s t d : : a l l o c a t o r <char> > , Widget> > > :: i n s e r t ( int ) / u s r / i n c l u d e / c ++/4.2.1/ b i t s / s t l m u l t i m a p . h : 3 3 9 : no t e : c a n d i d a t e s a r e : typename s t d : : R b t r e e < Key , s t d : : p a i r <const Key , Tp > , s t d : : S e l e c t 1 s t <s t d : : p a i r <const Key , Tp> > , Compare , typename A l l o c : : r ebind < s t d : : p a i r <const Key , Tp> > :: o t her > : : i t e r a t o r s t d : : multimap< Key , Tp , Compare , A l l o c > : : i n s e r t ( const s t d : : p a i r <const Key , Tp >&) [ with Key = s t d : : b a s i c s t r i n g <char , s t d : : c h a r t r a i t s <char > , s t d : : a l l o c a t o r <char> > , Tp = Widget , Compare = s t d : : l e s s <s t d : : b a s i c s t r i n g <char , s t d : : c h a r t r a i t s <char > , s t d : : a l l o c a t o r < char> > > , A l l o c = s t d : : a l l o c a t o r <s t d : : p a i r <const s t d : : b a s i c s t r i n g <char , s t d : : c h a r t r a i t s <char > , s t d : : a l l o c a t o r < char> > , Widget> > ] / u s r / i n c l u d e / c ++/4.2.1/ b i t s / s t l m u l t i m a p . h : 3 6 3 : no t e : typename s t d : : R b t r e e < Key , s t d : : p a i r <const Key , Tp > , s t d : : S e l e c t 1 s t <s t d : : p a i r <const Key , Tp> > , Compare , typename A l l o c : : r ebind < s t d : : p a i r <const Key , Tp> > :: o t her > : : i t e r a t o r s t d : : multimap< Key , Tp , Compare , A l l o c > : : i n s e r t ( typename s t d : : R b t r e e < Key , s t d : : p a i r <const Key , Tp > , s t d : : S e l e c t 1 s t <s t d : : p a i r <const Key , Tp> > , Compare , typename A l l o c : : r ebind < s t d : : p a i r <const Key , Tp> > :: o t her > : : i t e r a t o r , const s t d : : p a i r <const Key , Tp >&) [ with Key = s t d : : b a s i c s t r i n g <char , s t d : : c h a r t r a i t s <char > , s t d : : a l l o c a t o r <char> > , Tp = Widget , Compare = s t d : : l e s s < s t d : : b a s i c s t r i n g <char , s t d : : c h a r t r a i t s <char > , s t d : : a l l o c a t o r <char> > > , A l l o c = s t d : : a l l o c a t o r < s t d : : p a i r <const s t d : : b a s i c s t r i n g <char , s t d : : c h a r t r a i t s <char > , s t d : : a l l o c a t o r <char> > , Widget> > ] testmm . cpp : 3 8 : e r r o r : no matching f u n c t i o n for c a l l t o s t d : : multimap<int , int , intComp , s t d : : a l l o c a t o r <s t d : : p a i r <const int , int > > > :: i n s e r t ( int )
31
/ u s r / i n c l u d e / c ++/4.2.1/ b i t s / s t l m u l t i m a p . h : 3 3 9 : no t e : c a n d i d a t e s a r e : typename s t d : : R b t r e e < Key , s t d : : p a i r <const Key , Tp > , s t d : : S e l e c t 1 s t <s t d : : p a i r <const Key , Tp> > , Compare , typename A l l o c : : r ebind <s t d : : p a i r <const Key , Tp> > :: o t her > : : i t e r a t o r s t d : : multimap< Key , Tp , Compare , A l l o c > : : i n s e r t ( const s t d : : p a i r <const Key , Tp>&) [ with Key = int , Tp = int , Compare = intComp , A l l o c = s t d : : a l l o c a t o r <s t d : : p a i r <const int , int > > ] / u s r / i n c l u d e / c ++/4.2.1/ b i t s / s t l m u l t i m a p . h : 3 6 3 : no t e : typename s t d : : R b t r e e < Key , s t d : : p a i r <const Key , Tp > , s t d : : S e l e c t 1 s t <s t d : : p a i r <const Key , Tp> > , Compare , typename A l l o c : : r ebind <s t d : : p a i r <const Key , Tp> > :: o t her > : : i t e r a t o r s t d : : multimap< Key , Tp , Compare , A l l o c > : : i n s e r t ( typename s t d : : R b t r e e < Key , s t d : : p a i r <const Key , Tp > , s t d : : S e l e c t 1 s t <s t d : : p a i r <const Key , Tp> > , Compare , typename A l l o c : : r ebind <s t d : : p a i r <const Key , Tp> > :: o t her > : : i t e r a t o r , const s t d : : p a i r <const Key , Tp>&) [ with Key = int , Tp = int , Compare = intComp , A l l o c = s t d : : a l l o c a t o r <s t d : : p a i r <const int , int > > ] Workaround: Postprozessing oder besser statische Requirements uberpr ufung zur Compilezeit. Sehr leicht k onnen bei unpassenden Typparametern und anderen Problemen komplizierte und unverst andliche Compiler-Meldungen entstehen, was einfach mit der Tatsache zusammenh angt, dass die konkreten Anforderungen an die Typparameter unbekannt sind. Die Arbeit mit C++-Templates erfordert deshalb eine l uckenlose Dokumentation der Anforderungen an einen Typparameter. Durch Template-Metaprogrammierung k onnen die meisten Anforderungen (Basisklasse, Vorhandensein von Methoden, Kopierbarkeit, Zuweisbarkeit etc.) auch in speziellen Konstrukten abgefragt werden, wodurch sich lesbarere Fehlermeldungen ergeben. Obgleich sie standardkonform sind, werden diese Konstrukte jedoch nicht von allen Compilern unterst utzt. (Siehe http://de.wikipedia.org/wiki/Generische Programmierung in Java Abschnitt Das Konzept ) Why do templates produce such horrible error messages? In current C++, template errors are detected when a certain type argument does not support a certain operation (often expressed as the inability to convert one type to another or a failure of type deduction). It often happens deep into the instantiation tree. You need an equivalent of the stack trace to gure out where the root cause of the error is. Its called an instantiation stack and is dumped by the compiler upon a template error. It often spans several pages and contains unfamiliar names and implementation details of some library code. Siehe http://bartoszmilewski.wordpress.com/2010/06/24/c-concepts-a-postmortem/: Absatz Error Reporting .
32
template < c l a s s T> struct i s s a m e ; template < c l a s s T> struct i s b a s e o f ; template < c l a s s T> struct i s c o n v e r t i b l e ;
< c l a s s T> struct i s a r i t h m e t i c ; < c l a s s T> struct i s c o n s t ; < c l a s s T> struct i s t r i v i a l l y c o p y a b l e ; < c l a s s T> struct i s a b s t r a c t ; <c l a s s <c l a s s <c l a s s <c l a s s <c l a s s <c l a s s T> T> T> T> T> T> struct struct struct struct struct struct is same ; is base of ; is convertible ; has new operator ; has nothrow assign ; has nothrow constructor ;
< c l a s s T> struct i s e m p t y ; < c l a s s T> struct i s p o l y m o r p h i c ; < c l a s s T> struct has v i r t u a l d e s t r u c t o r ;
33
34
1.9 Template-Deklarationen zur Erzeugung von Objektdateien mit einer Ansammlung von Template-Instanzen
#include < io st r ea m > #include <cmath> using namespace s t d ; template <typename A r i t h m e t i c L i k e 1 , typename A r i t h m e t i c L i k e 2 > double geomMittel2 ( const A r i t h m e t i c L i k e 1& a , const A r i t h m e t i c L i k e 2& b ) { return s q r t ( abs ( a b ) ) ; } template double geomMittel2 <short , float >( const short &, const f l o a t &) ; template double geomMittel2 <int , float >( const int &, const f l o a t &) ; template double geomMittel2 <long , float >( const long &, const f l o a t &) ; template double geomMittel2 <float , float >( const f l o a t &, const f l o a t &) ; template double geomMittel2 <double , float >( const double &, const f l o a t &) ; template double geomMittel2 <long double , float >( const long double &, const f l o a t &) ; // . . . template double geomMittel2 <short , double >( const short &, const double &) ; template double geomMittel2 <int , double >( const int &, const double &) ; template double geomMittel2 <long , double >( const long &, const double &) ; template double geomMittel2 <float , double >( const f l o a t &, const double &) ; template double geomMittel2 <double , double >( const double &, const double &) ; template double geomMittel2 <long double , double >( const long double &, const double &) ; // . . . template double geomMittel2 <short , long double >( const short &,
35
const long double &) ; template double geomMittel2 <int , long double >( const int &, const long double &) ; template double geomMittel2 <long , long double >( const long &, const long double &) ; template double geomMittel2 <float , long double >( const f l o a t &, const long double &) ; template double geomMittel2 <double , long double >( const double &, const long double &) ; template double geomMittel2 <long double , long double >( const long double &, const long double &) ; Besser: Eine Sammlung von Objektdateien, die jeweils (nur) eine Instantiierung enth alt, damit die erzeugte Bibliothek nur die ben otigten Kompilationseinheiten einbinden l at.
36
37
In file included from /usr/include/c++/4.5/algorithm:63:0, from bad_error_eg.cpp:3: /usr/include/c++/4.5/bits/stl_algo.h: In Funktion void std::__insertion_sort(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = __ /usr/include/c++/4.5/bits/stl_algo.h:3358:4: instantiated from void std::__inplace_stable_sort(_RandomAccessIterator, _RandomAccessIterator) [with _Rando /usr/include/c++/4.5/bits/stl_algo.h:5415:2: instantiated from void std::stable_sort(_RAIter, _RAIter) [with _RAIter = __gnu_cxx::__normal_iterator<std:: bad_error_eg.cpp:8:41: instantiated from here /usr/include/c++/4.5/bits/stl_algo.h:2103:4: Fehler: no match for operator< in __i.__gnu_cxx::__normal_iterator<_Iterator, _Container>::operator* [wit /usr/include/c++/4.5/bits/stl_algo.h: In Funktion void std::__merge_without_buffer(_BidirectionalIterator, _BidirectionalIterator, _BidirectionalIterator, /usr/include/c++/4.5/bits/stl_algo.h:3364:7: instantiated from void std::__inplace_stable_sort(_RandomAccessIterator, _RandomAccessIterator) [with _Rando /usr/include/c++/4.5/bits/stl_algo.h:5415:2: instantiated from void std::stable_sort(_RAIter, _RAIter) [with _RAIter = __gnu_cxx::__normal_iterator<std:: bad_error_eg.cpp:8:41: instantiated from here /usr/include/c++/4.5/bits/stl_algo.h:2963:4: Fehler: no match for operator< in __middle.__gnu_cxx::__normal_iterator<_Iterator, _Container>::operator* /usr/include/c++/4.5/bits/stl_algo.h: In Funktion void std::__unguarded_linear_insert(_RandomAccessIterator) [with _RandomAccessIterator = __gnu_cxx::__nor /usr/include/c++/4.5/bits/stl_algo.h:2111:6: instantiated from void std::__insertion_sort(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAcce /usr/include/c++/4.5/bits/stl_algo.h:3358:4: instantiated from void std::__inplace_stable_sort(_RandomAccessIterator, _RandomAccessIterator) [with _Rando /usr/include/c++/4.5/bits/stl_algo.h:5415:2: instantiated from void std::stable_sort(_RAIter, _RAIter) [with _RAIter = __gnu_cxx::__normal_iterator<std:: bad_error_eg.cpp:8:41: instantiated from here /usr/include/c++/4.5/bits/stl_algo.h:2064:7: Fehler: no match for operator< in __val < __next.__gnu_cxx::__normal_iterator<_Iterator, _Container>::ope In file included from /usr/include/c++/4.5/vector:61:0, from bad_error_eg.cpp:1: /usr/include/c++/4.5/bits/stl_algobase.h: In Funktion _ForwardIterator std::lower_bound(_ForwardIterator, _ForwardIterator, const _Tp&) [with _ForwardItera /usr/include/c++/4.5/bits/stl_algo.h:2975:4: instantiated from void std::__merge_without_buffer(_BidirectionalIterator, _BidirectionalIterator, _Bidirect /usr/include/c++/4.5/bits/stl_algo.h:3364:7: instantiated from void std::__inplace_stable_sort(_RandomAccessIterator, _RandomAccessIterator) [with _Rando /usr/include/c++/4.5/bits/stl_algo.h:5415:2: instantiated from void std::stable_sort(_RAIter, _RAIter) [with _RAIter = __gnu_cxx::__normal_iterator<std:: bad_error_eg.cpp:8:41: instantiated from here /usr/include/c++/4.5/bits/stl_algobase.h:976:4: Fehler: no match for operator< in __middle.__gnu_cxx::__normal_iterator<_Iterator, _Container>::operat In file included from /usr/include/c++/4.5/algorithm:63:0, from bad_error_eg.cpp:3: /usr/include/c++/4.5/bits/stl_algo.h: In Funktion _FIter std::upper_bound(_FIter, _FIter, const _Tp&) [with _FIter = __gnu_cxx::__normal_iterator<std::comp /usr/include/c++/4.5/bits/stl_algo.h:2982:4: instantiated from void std::__merge_without_buffer(_BidirectionalIterator, _BidirectionalIterator, _Bidirect /usr/include/c++/4.5/bits/stl_algo.h:3364:7: instantiated from void std::__inplace_stable_sort(_RandomAccessIterator, _RandomAccessIterator) [with _Rando /usr/include/c++/4.5/bits/stl_algo.h:5415:2: instantiated from void std::stable_sort(_RAIter, _RAIter) [with _RAIter = __gnu_cxx::__normal_iterator<std:: bad_error_eg.cpp:8:41: instantiated from here /usr/include/c++/4.5/bits/stl_algo.h:2461:4: Fehler: no match for operator< in __val < __middle.__gnu_cxx::__normal_iterator<_Iterator, _Container>::o /usr/include/c++/4.5/bits/stl_algo.h: In Funktion _OIter std::merge(_IIter1, _IIter1, _IIter2, _IIter2, _OIter) [with _IIter1 = std::complex<float>*, _IIte /usr/include/c++/4.5/bits/stl_algo.h:2838:4: instantiated from void std::__merge_adaptive(_BidirectionalIterator, _BidirectionalIterator, _BidirectionalI /usr/include/c++/4.5/bits/stl_algo.h:3315:7: instantiated from void std::__stable_sort_adaptive(_RandomAccessIterator, _RandomAccessIterator, _Pointer, /usr/include/c++/4.5/bits/stl_algo.h:5417:2: instantiated from void std::stable_sort(_RAIter, _RAIter) [with _RAIter = __gnu_cxx::__normal_iterator<std:: bad_error_eg.cpp:8:41: instantiated from here /usr/include/c++/4.5/bits/stl_algo.h:5299:4: Fehler: no match for operator< in __first2.__gnu_cxx::__normal_iterator<_Iterator, _Container>::operator* /usr/include/c++/4.5/bits/stl_algo.h: In Funktion _BidirectionalIterator3 std::__merge_backward(_BidirectionalIterator1, _BidirectionalIterator1, _Bidirect /usr/include/c++/4.5/bits/stl_algo.h:2847:4: instantiated from void std::__merge_adaptive(_BidirectionalIterator, _BidirectionalIterator, _BidirectionalI /usr/include/c++/4.5/bits/stl_algo.h:3315:7: instantiated from void std::__stable_sort_adaptive(_RandomAccessIterator, _RandomAccessIterator, _Pointer, /usr/include/c++/4.5/bits/stl_algo.h:5417:2: instantiated from void std::stable_sort(_RAIter, _RAIter) [with _RAIter = __gnu_cxx::__normal_iterator<std:: bad_error_eg.cpp:8:41: instantiated from here /usr/include/c++/4.5/bits/stl_algo.h:2740:4: Fehler: no match for operator< in * __last2 < __last1.__gnu_cxx::__normal_iterator<_Iterator, _Container> /usr/include/c++/4.5/bits/stl_algo.h: In Funktion _OIter std::merge(_IIter1, _IIter1, _IIter2, _IIter2, _OIter) [with _IIter1 = __gnu_cxx::__normal_iterato /usr/include/c++/4.5/bits/stl_algo.h:3163:4: instantiated from void std::__merge_sort_loop(_RandomAccessIterator1, _RandomAccessIterator1, _RandomAccessI /usr/include/c++/4.5/bits/stl_algo.h:3261:4: instantiated from void std::__merge_sort_with_buffer(_RandomAccessIterator, _RandomAccessIterator, _Pointer) /usr/include/c++/4.5/bits/stl_algo.h:3312:4: instantiated from void std::__stable_sort_adaptive(_RandomAccessIterator, _RandomAccessIterator, _Pointer, /usr/include/c++/4.5/bits/stl_algo.h:5417:2: instantiated from void std::stable_sort(_RAIter, _RAIter) [with _RAIter = __gnu_cxx::__normal_iterator<std:: bad_error_eg.cpp:8:41: instantiated from here /usr/include/c++/4.5/bits/stl_algo.h:5299:4: Fehler: no match for operator< in __first2.__gnu_cxx::__normal_iterator<_Iterator, _Container>::operator* /usr/include/c++/4.5/bits/stl_algo.h: In Funktion _OIter std::merge(_IIter1, _IIter1, _IIter2, _IIter2, _OIter) [with _IIter1 = std::complex<float>*, _IIte /usr/include/c++/4.5/bits/stl_algo.h:3163:4: instantiated from void std::__merge_sort_loop(_RandomAccessIterator1, _RandomAccessIterator1, _RandomAccessI /usr/include/c++/4.5/bits/stl_algo.h:3263:4: instantiated from void std::__merge_sort_with_buffer(_RandomAccessIterator, _RandomAccessIterator, _Pointer) /usr/include/c++/4.5/bits/stl_algo.h:3312:4: instantiated from void std::__stable_sort_adaptive(_RandomAccessIterator, _RandomAccessIterator, _Pointer, /usr/include/c++/4.5/bits/stl_algo.h:5417:2: instantiated from void std::stable_sort(_RAIter, _RAIter) [with _RAIter = __gnu_cxx::__normal_iterator<std:: bad_error_eg.cpp:8:41: instantiated from here /usr/include/c++/4.5/bits/stl_algo.h:5299:4: Fehler: no match for operator< in * __first2 < * __first1
38
C++11:
SGI:
39
40
template <typename R a ndo mAccessIt er a t o r > R a ndo mAccessIt er a t o r f o o ( R a ndo mAccessIt er a t o r from , R a ndo mAccessIt er a t o r t o ) { // t h i s t e m p l a t e s h o u l d o n l y be used w i t h // random a c c e s s i t e r a t o r s . . . // // d e t a i l g o e s h e r e . . . r e v e r s e ( from , t o ) ; return from ; }; int main ( ) { s t d : : v e c t o r <float > v ; // s t d : : s e t < f l o a t > v ; v . i n s e r t ( v . end ( ) , 3 . 1 4 ) ; v . i n s e r t ( v . end ( ) , 1 5 . 1 5 ) ; f o o ( v . b e g i n ( ) , v . end ( ) ) ; copy ( v . b e g i n ( ) , v . end ( ) , s t d : : o s t r e a m i t e r a t o r <float >( s t d : : cout , ) ) ; s t d : : co ut << s t d : : e n d l ; } wird einwandfrei u bersetzt > make CXXFLAGS="-std=c++0x" ra2b
41
g++ -std=c++0x -g -I. -I/home/user/include und funktioniert einwandfrei, f ur int main ( ) { // s t d : : v e c t o r < f l o a t > v ; s t d : : s e t <float > v ; // . . . erscheint jedoch keine vern unftige Fehlermeldung
ra2b.cpp
-o ra2b
> make CXXFLAGS="-std=c++0x" ra2b g++ -std=c++0x -g -I. -I/home/buhl/include ra2b.cpp -o ra2b In file included from /usr/include/c++/4.5/bits/char_traits.h:41:0, from /usr/include/c++/4.5/ios:41, from /usr/include/c++/4.5/ostream:40, from /usr/include/c++/4.5/iostream:40, from ra2b.cpp:1: /usr/include/c++/4.5/bits/stl_algobase.h: In static member function static void /usr/include/c++/4.5/bits/stl_algobase.h:138:7: instantiated from void std::it /usr/include/c++/4.5/bits/stl_algo.h:1395:6: instantiated from void std::__rev /usr/include/c++/4.5/bits/stl_algo.h:1441:7: instantiated from void std::rever ra2b.cpp:19:4: instantiated from RandomAccessIterator foo(RandomAccessIterator ra2b.cpp:30:28: instantiated from here /usr/include/c++/4.5/bits/stl_algobase.h:89:11: Fehler: Zuweisung der schreibgesc /usr/include/c++/4.5/bits/stl_algobase.h:138:7: instantiated from void std::it /usr/include/c++/4.5/bits/stl_algo.h:1395:6: instantiated from void std::__rev /usr/include/c++/4.5/bits/stl_algo.h:1441:7: instantiated from void std::rever ra2b.cpp:19:4: instantiated from RandomAccessIterator foo(RandomAccessIterator ra2b.cpp:30:28: instantiated from here /usr/include/c++/4.5/bits/stl_algobase.h:90:11: Fehler: Zuweisung der schreibgesc make: *** [ra2b] Fehler 1 RandomAccessIterator
42
Durch ein geeignetes statisches Assert der Art #include #include #include #include #include #include #include #include < io st r ea m > < a lg o r it hm > <i t e r a t o r > <v e c t o r > <s e t > <complex > < b o o s t / s t a t i c a s s e r t . hpp> < b o o s t / t y p e t r a i t s . hpp>
template <typename R a ndo mAccessIt er a t o r > R a ndo mAccessIt er a t o r f o o ( R a ndo mAccessIt er a t o r from , R a ndo mAccessIt er a t o r t o ) { // t h i s t e m p l a t e can o n l y be used w i t h // random a c c e s s i t e r a t o r s . . . typedef typename s t d : : i t e r a t o r t r a i t s < R a ndo mAccessIt er a t o r > :: i t e r a t o r c a t e g o r y c a t ; static assert ( ( : : boost : : i s c o n v e r t i b l e < cat , const s t d : : r a n d o m a c c e s s i t e r a t o r t a g & > :: v a l u e ) , no random a c c e s s i t e r a t o r ) ; // // d e t a i l g o e s h e r e . . . r e v e r s e ( from , t o ) ; return from ; }; int main ( ) { // s t d : : v e c t o r < f l o a t > v ; s t d : : s e t <float > v ; v . i n s e r t (v . begin ( ) , 3 . 1 4 ) ; v . i n s e r t (v . begin ( ) , 1 5 . 1 5 ) ; f o o ( v . b e g i n ( ) , v . end ( ) ) ; copy ( v . b e g i n ( ) , v . end ( ) , s t d : : o s t r e a m i t e r a t o r <float >( s t d : : cout , ) ) ; s t d : : co ut << s t d : : e n d l ; } wird jedoch der falsche aktuelle generische Parametertyp gemeldet: make CXXFLAGS="-std=c++0x" ra2
43
g++ -std=c++0x -g -I. -I/home/buhl/include ra2.cpp -o ra2 ra2.cpp: In Funktion RandomAccessIterator foo(RandomAccessIterator, RandomAccess ra2.cpp:36:28: instantiated from here ra2.cpp:18:4: Fehler: statische Behauptung gescheitert: "no random access iterato ...
template <typename T> struct a b s t r a c t C l a s s { s t a t i c a s s e r t ( f a l s e , This c l a s s may not be instantiated ! ) ; // . . . }; int main ( ) { a b s t r a c t C l a s s <int > ac ; s t d : : co ut << s t d : : e n d l ; } Beachte eventuell:
http://www.boost.org/doc/libs/1 47 0/doc/html/boost staticassert.html#boost staticassert.templates
44
45
46
using namespace s t d ; template <typename A r i t h m e t i c L i k e 1 , typename A r i t h m e t i c L i k e 2 > typename : : b o o s t : : e n a b l e i f < : : b o o s t : : i s a r i t h m e t i c <A r i t h m e t i c L i k e 1 > , double > : : type g eo mMittel2 ( const A r i t h m e t i c L i k e 1& a , const A r i t h m e t i c L i k e 2& b ) { return s q r t ( abs ( a b ) ) ; } // u e b e r s e t z e mit s t d=c++0x // oder g++ CXXFLAGS= s t d=c++0x . . . i nt main ( ) { co ut << co ut << co ut << co ut << co ut << // c o u t
g eo mMittel2 ( 3 . 0 , 3 0 0 . 0 ) << e n d l ; g eo mMittel2 ( 3 , 3 0 0 . 0 ) << e n d l ; g eo mMittel2 ( 3 , 3 0 0 . 0 ) << e n d l ; g eo mMittel2 ( 3 , 3 0 0 ) << e n d l ; g eo mMittel2 ( 3 . 0 , c ) << e n d l ; << g e o m M i t t e l 2 ( 3 . 0 , c ) << e n d l ;
return 0 ; }
47
48
Prototypen in Headerdateien Wichtig: Bei Prototypen unterscheidet C zwischen einer leeren Parameterliste und einer Parameterliste mit void . Ist die Parameterliste leer, so bedeutet dies, dass die Funktion eine nicht denierte Anzahl an Parametern besitzt. Das Schl usselwort void gibt an, dass der Funktion keine Werte u urfen. bergeben werden d (Funktionsprototypen in C) C functions without prototypes Im C++11-Standard (zumindest schon dokumentarisch, d.h. nicht maschinell u uft) berpr zus atzlich: Descriptions of function semantics contain the following elements (as appropriate): Requires: the preconditions for calling the function Eects: the actions performed by the function Synchronization: the synchronization operations (1.10) applicable to the function Postconditions: the observable results established by the function Returns: a description of the value(s) returned by the function Throws: any exceptions thrown by the function, and the conditions that would cause the exception Complexity: the time and/or space complexity of the function Remarks: additional semantic constraints on the function Error conditions: the error conditions for error codes reported by the function. Notes: non-normative comments about the function Ein Beispiel: l o g i c e r r o r ( const s t r i n g& wha t a r g ) ; E f f e c t s : C o n s t r u c t s an o b j e c t o f c l a s s l o g i c e r r o r . P o s t c o n d i t i o n : strcmp ( what ( ) , wha t a r g . c s t r ( ) ) == 0 . Bemerkung: age/ DbC in C++(?) Software durch Vertr Not ready for C++0x, but open to resubmit in future
49
ankter 1.17 Ausblick: C++2x eventuell mit eingeschr Generizit at: Concepts (Prototypen von Klassen)
http://www.generic-programming.org/languages/conceptcpp/tutorial/
template<s t d : : C o p y C o n s t r u c t i b l e T> r e q u i r e s Addable <T> T sum (T a r r a y [ ] , i nt n ) { T result = 0; for ( i nt i = 0 ; i < n ; ++i ) r e s u l t = r e s u l t + array [ i ] ; return r e s u l t ; }
Statt einer buchstabengetreuen Uberpr ufung auf Einhaltung der Konzepteigenschaften mittels der auto-Konzeptdenition kann man durch concept maps auch eine mit tels Ubersetzung einzelner Operationen/Typen erreichbare Erf ullung der Konzept Eigenschaften denieren:
c o n c e p t Stack <typename X> { typename v a l u e t y p e ; void push (X&, const v a l u e t y p e &) ; void pop (X&) ; v a l u e t y p e top ( const X&) ; bool empty ( const X&) ; }; template<typename T> concept map Stack <s t d : : v e c t o r <T>> { typedef T v a l u e t y p e ; void push ( s t d : : v e c t o r <T >& v , const T& x ) { v . push ba ck ( x ) ; } void pop ( s t d : : v e c t o r <T >& v ) { v . pop back ( ) ; } T top ( const s t d : : v e c t o r <T>& v ) { return v . back ( ) ; } bool empty ( const s t d : : v e c t o r <T>& v ) { return v . empty ( ) ; } };
50
using namespace s t d ; auto c o n c e p t HasAbs<typename T> { typename r e s u l t t y p e ; r e s u l t t y p e abs ( const T&) ; } auto c o n c e p t HasPower<typename T>{ typename r e s u l t t y p e ; r e s u l t t y p e pow ( const T&, i nt ) ; } auto c o n c e p t HasPowerd<typename T>{ r e q u i r e s F l o a t i n g P o i n t L i k e <T> ; double pow ( const T&, const T&) ; } template < i nt p = 2 , I n p u t I t e r a t o r I n p u t I t e r , F l o a t i n g P o i n t L i k e T> r e q u i r e s True<p >= 1 > , HasAbs< I n p u t I t e r : : v a l u e t y p e > , HasPowerd<T> , HasPower<HasAbs< I n p u t I t e r : : v a l u e t y p e > : : r e s u l t t y p e > , Ha sP lusAssig n<T, HasPower<HasAbs< I n p u t I t e r : : v a l u e t y p e > : : r e s u l t t y p e > : : r e s u l t t y p e > T pNorm( I n p u t I t e r f i r s t , I n p u t I t e r l a s t , T i n i t ) { for ( ; f i r s t != l a s t ; f i r s t ++) { i n i t += pow ( abs ( f i r s t ) , p ) ; }; return pow ( ( i n i t ) , ( 1 . 0 / p ) ) ; } i nt main ( ) { v e c t o r <double> TD ( 2 ) ; TD[ 0 ] = 2 0 0 . 0 ; TD[ 1 ] = 0 . 0 ; double r e s = pNorm<3>(TD. b e g i n ( ) , TD. end ( ) , 0 . 0 f ) ; co ut << r e s << s i z e o f : << s i z e o f (pNorm(TD. b e g i n ( ) , TD. end ( ) , 0 . 0 f ) ) << e n d l ; double TestData [ ] = { 1 1 0 . 0 , 1 0 . 0 , 1 0 . 0 } ; co ut << pNorm( TestData , TestData + 3 , 0 . 0 ) << s i z e o f : << s i z e o f ( pNorm( TestData , TestData + 3 , 0 . 0 ) ) << e n d l ;
51
double TestData2 [ ] = { 1 0 . 0 , 1 0 . 0 , 1 0 . 0 } ; co ut << pNorm<1>(TestData2 , TestData2 + 3 , 0 . 0 l ) << s i z e o f : << s i z e o f ( pNorm<1>(TestData2 , TestData2 + 3 , 0.0 l ) ) << e n d l ;
return 0 ; }
Dabei wird aus das Konzept HasPlusAssign<T, U> der C++0x Standard Library benutzt: auto c o n c e p t HasPlusAssign <typename T, typename U = T> { typename r e s u l t t y p e ; r e s u l t t y p e operator+=(T&, const U&) ; } (vergleiche Foundational Concepts for the C++0x Standard Library (Revision 5)) Link zu conceptg++: http://www.generic-programming.org/software/ConceptGCC/download.php Zitat: ConceptC++ makes programming with C++ templates easier, because the compiler can type-check templates when they are dened, so mistakes show up earlier. Real support for Generic Programming also means that many of the template tricks that are needed in standard C++ are no longer necessary, and, yes, it provides much-improved error messages than we get with C++ compilers today. C++11 without Concepts C++ Concepts: a Postmortem
52
53
54
55
56
{ s o r t ( v . b e g i n ( ) , v . end ( ) ) ; sort (v) ; // . . . } concept maps: Zeiger sind Vorbild f ur Iteratoren, ihnen fehlt jedoch der assoziierte Typ value type. Dem kann man mit einer concept map abhelfen: template<typename T> concept map F o r w a r d I t e r a t o r <T> { typedef T v a l u e t y p e ; }; Axioms: c o n c e p t Semigroup <typename Op, typename T> : Co pyCo nst r uct ibl e <T> { T operator ( ) (Op, T, T) ; axiom A s s o c i a t i v i t y (Op op , T x , T y , T z ) { op ( x , op ( y , z ) ) <=> op ( op ( x , y ) , z ) ; } } c o n c e p t Monoid<typename Op, typename T> : Semigroup <Op, T> { T i d e n t i t y e l e m e n t (Op) ; axiom I d e n t i t y (Op op , T x ) { op ( x , i d e n t i t y e l e m e n t ( op ) ) <=> x ; op ( i d e n t i t y e l e m e n t ( op ) , x ) <=> x ; } } // i n c o n c e p t T o ta l O rd e r : axiom T r a n s i t i v i t y (Op op , T x , T y , T z ) { i f ( op ( x , y ) && op ( y , z ) ) op ( x , z ) <=> true ; // c o n d i t i o n a l e q u i v a l e n c e } // one way // a n o t h e r way
57
1.22 ConceptC++-Tutorial
vergleiche http://www.generic-programming.org/languages/conceptcpp/tutorial/ Ausgangspunkt: ein oder mehrere konkrete Algorithmen double sum ( double a r r a y [ ] , int n ) { double r e s u l t = 0 ; for ( int i = 0 ; i < n ; ++i ) r e s u l t = r e s u l t + array [ i ] ; return r e s u l t ; } Erster Verallgemeinerungsschritt: template<typename T> T sum (T a r r a y [ ] , int n ) { T result = 0; for ( int i = 0 ; i < n ; ++i ) r e s u l t = r e s u l t + array [ i ] ; return r e s u l t ; } f uhrt beim ersten Instantiierungsversuch struct pod { int i ; }; int main ( ) { pod v a l u e s [ 3 ] = { { 1 } , { 2 } , { 3 } } ; sum ( v a l u e s , 3 ) ; return 0 ; } zu Fehlermeldungen:
> conceptg++ array1-1.C array1-1.cc: In function T sum(T*, int) [with T = pod]: array1-1.cc:19: instantiated from here array1-1.cc:5: error: conversion from int to non-scalar type pod requested array1-1.cc:7: error: no match for operator+ in result + *((+(((unsigned int)i) * 4u)) + array)
58
Die Spezikation eines notwendigen Konzepts: #include < co ncept s > template<s t d : : C o p y C o n s t r u c t i b l e T> T sum (T a r r a y [ ] , int n ) { T result = 0; for ( int i = 0 ; i < n ; ++i ) r e s u l t = r e s u l t + array [ i ] ; return r e s u l t ; } Jetzt lautet die Fehlermeldung:
> conceptg++ array2.C array2.cpp: In function T sum(T*, int): array2.cpp:5: error: conversion from int to non-scalar type T requested array2.cpp:7: error: no match for operator+ in result + array[i]
Vervollst andigung des Sets der n otigen Konzepte: template<s t d : : C o p y C o n s t r u c t i b l e T> r e q u i r e s Addable <T> T sum (T a r r a y [ ] , int n ) { T result = 0; for ( int i = 0 ; i < n ; ++i ) r e s u l t = r e s u l t + array [ i ] ; return r e s u l t ; } Fehlermeldung:
array3.cpp: In function T sum(T*, int): array3.cpp:10: error: conversion from int to non-scalar type T requested array3.cpp:12: error: no match for operator= in result = Addable<T>::operator+(result, array[i])
Erneute Vervolllst andigung des Sets der ben otigten Konzepte: template<s t d : : C o p y C o n s t r u c t i b l e T> r e q u i r e s Addable <T> , A s s i g n a b l e <T> T sum (T a r r a y [ ] , int n ) { T result = 0; for ( int i = 0 ; i < n ; ++i ) r e s u l t = r e s u l t + array [ i ] ; return r e s u l t ; } Immer noch Fehler:
array4.cpp: In function T sum(T*, int): array4.cpp:14: error: conversion from int to non-scalar type T requested
59
Letzte Erweiterung der ben otigten Konzepte: auto c o n c e p t I n t C o n s t r u c t i b l e <typename T> { T : : T( int ) ; }; template< s t d : : C o p y C o n s t r u c t i b l e T> r e q u i r e s Addable <T> , A s s i g n a b l e <T> , I n t C o n s t r u c t i b l e <T> T sum (T a r r a y [ ] , int n ) { T result = 0; for ( int i = 0 ; i < n ; ++i ) r e s u l t = r e s u l t + array [ i ] ; return r e s u l t ; } und fehlerlose Ubersetzung. Wir haben das Konzept f ur die generische Funktion sum() zusammengestellt. Bemerkung: Nach Muster der STL (siehe zum Beispiel accumulate() w are die folgende generische Version besser: template< s t d : : C o p y C o n s t r u c t i b l e T> r e q u i r e s Addable <T> , A s s i g n a b l e <T> T sum (T a r r a y [ ] , int n , T r e s u l t ) { for ( int i = 0 ; i < n ; ++i ) r e s u l t = r e s u l t + array [ i ] ; return r e s u l t ; }
60
Zweiter Verallgemeinerungsschritt: (Zeiger statt Felder) template<s t d : : C o p y C o n s t r u c t i b l e T> r e q u i r e s Addable <T> , A s s i g n a b l e <T> T sum (T f i r s t , T l a s t , T r e s u l t ) { for ( ; f i r s t != l a s t ; ++f i r s t ) result = result + f irs t ; return r e s u l t ; } Ubersetzung ohne Fehlermeldung! Dritter Verallgemeinerungsschritt: (Iteratoren statt Zeiger)
template< F o r w a r d I t e r a t o r I t e r > r e q u i r e s Addable < I t e r : : v a l u e t y p e > , A s s i g n a b l e < I t e r : : v a l u e t y p e > I t e r : : v a l u e t y p e sum ( I t e r f i r s t , I t e r l a s t , I t e r : : v a l u e t y p e r e s u l t ) { f o r ( ; f i r s t != l a s t ; ++f i r s t ) result = result + f i r s t ; return r e s u l t ; }
f uhrt zur Fehlermeldung, dass Zeiger keine Forwarditeratoren sin.Die concept map concept map F o r w a r d I t e r a t o r <double> { typedef double v a l u e t y p e ; }; behebt diese Unkenntnis.
61
Um alle Zeiger zu Forwarditeratoren zu machen, kann man folgende Konzeptmap einf uhren: template<typename T> concept map F o r w a r d I t e r a t o r <T> { typedef T v a l u e t y p e ; }; Retroaktive Konzepterfu llung: Soll Die Klasse Color c l a s s Co lo r { public : Co lo r ( ) ; Co lo r mix ( const Co lo r& o t h e r ) const ; // . . . }; das Konzept Addable erf ullen, ist das durch
concept map Addable <Color > { C o l o r operator +( const C o l o r& x , const C o l o r& y ) { return x . mix ( y ) ; } };
template< F o r w a r d I t e r a t o r I t e r , A s s i g n a b l e T> r e q u i r e s Addable <T> T sum ( I t e r f i r s t , I t e r l a s t , T r e s u l t ) { for ( ; f i r s t != l a s t ; ++f i r s t ) result = result + f i rs t ; return r e s u l t ; } Fehlermeldung: op1.cpp: In function T sum(Iter, Iter, T): op1.cpp:26: error: no match for operator+ in result + * first op1.cpp:3: note: candidates are: T Addable<T>::operator+(const T&, const T&) Neue Konzeptmap: auto c o n c e p t Addable <typename T, typename U = T> { T operator +(T x , U y ) ; }; template< F o r w a r d I t e r a t o r I t e r , A s s i g n a b l e T>
62
r e q u i r e s Addable <T, v a l u e t y p e > T sum ( I t e r f i r s t , I t e r l a s t , T r e s u l t ) { for ( ; f i r s t != l a s t ; ++f i r s t ) result = result + f irs t ; return r e s u l t ; } Fehlerfrei! Aufgabe: Uberlege eine allgemeinere sum-Version, die Container statt mittels + mit ungt. einer beliebigen zweiargumentigen Operation op(,) verj Eine Sammlung von Konzepten ndet man unter ConceptC++ Specication.
63
1.24 SFINAE
SFINAE als Voraussetzung f ur enable if: struct Test { typedef int f o o ; }; template <typename T> void f ( typename T : : f o o ) {} // D e f i n i t i o n #1 template <typename T> void f (T) {}
// D e f i n i t i o n #2
int main ( ) { f <Test > (10) ; // C a l l #1. f <int > (10) ; // C a l l #2. Without e r r o r ( even th o ug h t h e r e i s no i n t : : f o o ) t h a n k s t o SFINAE . }
64
65
1.26 POD-Typen
POD Types
66
67
Compiler brauchen Templates bis zur entg ultigen Instantiierung nicht zu u bersetzen, also auch nicht syntaktisch zu analysieren. Das Auftreten m oglicher Fehlermeldungen ist deshalb bis zur Instantiierung aufgeschoben. Um eine vollst andige Testabdeckung zu erreichen, ben otigt man ein Urmuster des Gebrauchs aller nach Konzept vorgeschriebenen Operationen, die testcompiliert vorhandene fehlende Operationsdenitionen aufdecken w urde: einen Archetyp des Konzepts. Die urspr unglich in den C++0x geplanten Konzepte h atten Archtypen automatisch erzeugt und benutzt, somit die Templatedenition automatisch vollst andig typgechecked. Das bisherige C++-template-Handling l at m ogliche in der Dokumentation einer Template-Bibliothek unerw ahne Requirements eines generischen Objekts lange unentdeckt und frustriert zu unvorhergesehenen Zeiten dessen Benutzer mit einer bis dahin nie aufgetretenen Fehlermeldung(skaskade): Motivierendes BCCL-Beispiel. Bei Benutzung der BCCL hat man eigene Konzepte selbst mit Archetypen auszustatten und diese testzucompilieren (siehe Abschmitt 1.21.3). Die in der BCCL vordenierten f ur die STL n otigen Konzepte sind in der Datei boost/concept archetype.hpp mit Archetypen ausgestattet. Zum Beispiel das Konzept InputIterator mit den geforderten Operationen ++i, (void)i++, *i++,*i; Defaultkonstruktor, operator=, operator-> (TrivialIterator); Kopierkonstruktor, swap() (Assignable); operator==, operator!= (EqualtityComparable); Defaultkonstruktor (DefaultConstructible) (vgl. STL InputIterator) und dem folgenden Archetyp daf ur: //
============================================================== // I t e r a t o r Arc h e typ e C l a s s e s template < c l a s s T, int I = 0> class i n p u t i t e r a t o r a r c h e t y p e { private : typedef i n p u t i t e r a t o r a r c h e t y p e s e l f ; public : typedef s t d : : i n p u t i t e r a t o r t a g i t e r a t o r c a t e g o r y ; typedef T v a l u e t y p e ; struct r e f e r e n c e {
68
operator const v a l u e t y p e &() const { return s t a t i c o b j e c t <T > : : g e t ( ) ; } }; typedef const T p o i n t e r ; typedef s t d : : p t r d i f f t d i f f e r e n c e t y p e ; s e l f & operator =( const s e l f &) { return t h i s ; } bool operator==(const s e l f &) const { return true ; } bool operator !=( const s e l f &) const { return true ; } r e f e r e n c e operator ( ) const { return r e f e r e n c e ( ) ; } s e l f & operator ++() { return t h i s ; } s e l f operator++( int ) { return t h i s ; } }; BCCL unterst utzt die Uberpr ufung von semantischen Requirements wie z.B. Benutzbarkeit in Multipass-Algorithmen ... nicht! BCCL unterst utzt das Syntaxremappping (tempor ares renaming, Context maps) nicht. BCCL unterst utzt Kontext-basiertes Uberladen nicht. (Ausweg: enable if mit Concept Traits)
69
70
#endif ignore unused variable warning ( c ) ; } TT a ; }; Iterator Concept Checking Classes template < c l a s s TT, c l a s s ValueT> struct O u t p u t I t e r a t o r C o n c e p t { void c o n s t r a i n t s ( ) { f u n c t i o n r e q u i r e s < Assig na bleCo ncept <TT > > () ; ++i ; // r e q u i r e p r e i n c r e m e n t o p e r a t o r i ++; // r e q u i r e p o s t i n c r e m e n t o p e r a t o r i++ = t ; // r e q u i r e p o s t i n c r e m e n t and a s s i g n m e n t } TT i , j ; ValueT t ; }; Function Object Concept Checking Classes template < c l a s s Func , c l a s s Return > struct GeneratorConcept { void c o n s t r a i n t s ( ) { const Return& r = f ( ) ; // r e q u i r e o p e r a t o r ( ) member f c t ignore unused variable warning ( r ) ; } Func f ; }; Container Concept Checking Classes template < c l a s s Container > struct Co nt a iner Co ncept { typedef typename Co nt a iner typedef typename Co nt a iner difference type ; typedef typename Co nt a iner typedef typename Co nt a iner const reference ;
: : value type value type ; : : difference type : : size type size type ; : : const reference
71
typedef typename Co nt a iner : : c o n s t p o i n t e r c o n s t p o i n t e r ; typedef typename Co nt a iner : : c o n s t i t e r a t o r c o n s t i t e r a t o r ; void c o n s t r a i n t s ( ) { f u n c t i o n r e q u i r e s < I n p u t I t e r a t o r C o n c e p t<c o n s t i t e r a t o r > > () ; f u n c t i o n r e q u i r e s < Assig na bleCo ncept <Container > > () ; const constraints (c) ; } void c o n s t c o n s t r a i n t s ( const Co nt a iner& c ) { i = c . begin ( ) ; i = c . end ( ) ; n = c . size () ; n = c . max size ( ) ; b = c . empty ( ) ; } Co nt a iner c ; bool b ; const iterator i ; size type n; };
72
uck (2003..2008) und vorw arts 2.3 Ein Blick zur (202x)? Usage-Pattern oder Pseudosignatur
(Am Anfang) Usage Pattern-FallstudienAnsatz: Stroustrup: N1510 (2003) template< c l a s s Va lue t ype > struct F o r w a r d i t e r a t o r { s t a t i c void c o n s t r a i n t s ( F o r w a r d i t e r a t o r p ) { F o r w a r d i t e r a t o r q = p ; p = q ; // can be c o p i e d p++; ++p ; // can be i n c re m e n te d V a l u e t y p e v = p ; // p o i n t s t o V a l u e t y p e s } // . . . } // . . . c o n c e p t Element { c o n s t r a i n t s ( Element e1 , Element e2 ) { bool b =e1 <e2 ; // Elements can be compared u s i n g < // and t h e r e s u l t can be used as a // b o o l swap ( e1 , e2 ) ; // Elements can be swapped } }; // . . . c o n c e p t Add { // We can copy and add Adds c o n s t r a i n t s (Add x ) { Add y = x ; x = y ; x = x+y ; Add xx = x+y ; } }; // . . . Der Pseudosignatur-Ansatz f uhrt zun achst zu Problemen bei ahnlichen unterschiedlichen Signaturen.
73
Var<>-Platzhalter, where, &&(2006): Stroustrup: Specifying C++ Concepts c o n c e p t Mutable fwd <typename I t e r , typename T> { Var< I t e r > p ; // a v a r i a b l e o f t y p e I t e r . Var<const T> v ; // a v a r i a b l e o f t y p e c o n s t T. Iter q = p; bool b = ( p != q ) ; // an I t e r must be copy a b l e // // // // // // // // // must s u p p o r t != o p e r a t i o n , and t h e r e s u l t i n g e x p r e s s i o n must be c o n v e r t i b l e t o b o o l must s u p p o r t pre increment , no r e q u i r e m e n t s on t h e r e s u l t t y p e must be a b l e t o d e r e f e r e n c e p , and a s s i g n a c o n s t T t o t h e r e s u l t o f t h a t d e r e f e r e n c e ; no r e q u i r e m e n t s on t h e r e s u l t t y p e
++p ;
p = v ;
}; // . . . c o n c e p t Small <typename T, int N> where s i z e o f (T) <= N { }; // . . . c o n c e p t C<typename X> where C1<X> && C2<X> { }; // . . . c o n c e p t Mutable fwd <typename I t e r , typename T> { Var< I t e r > p ; // p l a c e h o l d e r f o r v a r i a b l e o f t y p e I t e r . Var<const T> v ; Var<T> v2 ; // . . . as b e f o r e . . . p = v ; // we can w r i t e t o p v2 = p ; // we can re a d from p }; // . . .
74
c o n c e p t F o r w a r d i t e r a t o r <typename I t e r > { Var< I t e r > p ; // a v a r i a b l e o f t y p e I t e r . typename I t e r : : v a l u e t y p e // must have a named member // a s s o c i a t e d t y p e v a l u e t y p e . Iter q = p; // an I t e r must be copy a b l e bool b = ( p != q ) ; // must s u p p o r t == and != b = ( p == q ) ; // o p e r a t i o n s , and t h e r e s u l t i n g // e x p r e s s i o n s must be c o n v e r t i b l e // t o b o o l . ++p ; // must s u p p o r t pre and p++; // p o s t i n c re m e n t o p e r a t i o n s , no // a s s um p ti o n on t h e r e s u l t t y p e }; // . . . c o n c e p t C o p y c o n s t r u c t i b l e <typename T> { Var<T> a ; T b = a; // copy c o n s t r u c t i o n T c(a) ; // d i r e c t copy c o n s t r u c t i o n }; c o n c e p t A s s i g n a b l e <typename T, typename U = T> { Var<T> a ; Var<const U> b ; a = b; // copy ( non d e s t r u c t i v e re a d ) }; c o n c e p t Movable <typename T, typename U = T> { Var<T> a ; Var<U> b ; a = b; // p o t e n t i a l l y d e s t r u c t i v e re a d }; c o n c e p t E q u a l i t y c o m p a r a b l e <typename T, typename U = T> { Var<const T> a ; Var<const U> b ; bool eq = ( a == b ) ; bool neq = ( a != b ) ; }; // . . . c o n c e p t Container <typename X> { X : : X( int n ) ; X : : X( ) ; bool X : : empty ( ) const ; }
75
Pseudo-Signaturen (2008..2009): C++11-FAQ: Since it is likely that concepts in some form or other will be part of a later version of C++, I have not deleted the concept sections from this document. (Stroustrup) ConceptClang (2011): c o n c e p t Hashset <typename X> : HasEmpty<X> { typename element ; r e q u i r e s ( Hashable <element >) ; int s i z e (X) ; } // m o d e l i n g template<typename K > r e q u i r e s ( Hashable <K>) concept map Hashset < l i s t <K>> { typedef K element ; int s i z e ( l i s t <K> m) { . . . } } // . . . Concepts: Linguistic Support for Generic Programming in C++ ConceptC++ Publications The C++0x Concepts Eort
76
77
Kochrezept: Concept Checking Template Class mit Namen des Konzepts erstellen Notwendige Vater-Konzepte mittels Vererbung spezizieren (hier: Assignable und EqualitiyComparable) N otige assoziierte Typen mittels typedef als Membertype denieren otige Einschr ankungen an die assoziierten Ty Durch BOOST CONCEPT ASSERT() n pen formulieren Mittels BOOST CONCEPT USAGE() die geforderten Eigenschaften (Operationen) der das Konzept erf ullenden Klassen (als Usage-Pattern) spezizieren otige Objektdeklarationen als Datamember der F ur BOOST CONCEPT USAGE() n Concept Checking Class und eventuell n otige Funktionsdeklarationen (wie hier same type(.,.)) vornehmen
78
79
80
3 Trait-Klassen als Mittel der Absicherung vorhandener Eigenschaften aktueller generischer Parameter
3.1 Type Traits in D (Template Constraints)
Eingeschr ankte Generizit at in D: // Returns t r u e i f i n s t a n c e s o f t y p e T can be added template i s A d d a b l e (T) { // Works by a t t e m p t i n g t o add two i n s t a n c e s o f t y p e T const i s A d d a b l e = t r a i t s ( co mpiles , (T t ) { return t + t ; }) ; } int Foo (T) (T t ) i f ( i s A d d a b l e ! ( T) ) { return 3 ; } // . . . und deren Anwendung f ur ADTs: template i s S t a c k (T) { const i s S t a c k = t r a i t s ( co mpiles , (T t ) { T. v a l u e t y p e v = top ( t ) ; push ( t , v ) ; pop ( t ) ; i f ( empty ( t ) ) { } }) ;
81
82
83
template < c l a s s T> struct i s p o l y m o r p h i c ; template < c l a s s T> struct i s a b s t r a c t ; template < c l a s s T> struct i s s i g n e d ; template < c l a s s T> struct i s u n s i g n e d ; template < c l a s s T, c l a s s . . . Args> struct i s c o n s t r u c t i b l e ; template < c l a s s T> struct i s d e f a u l t c o n s t r u c t i b l e ; template < c l a s s T> struct i s c o p y c o n s t r u c t i b l e ; template < c l a s s T> struct i s m o v e c o n s t r u c t i b l e ; template < c l a s s T, c l a s s U> struct i s a s s i g n a b l e ; template < c l a s s T> struct i s c o p y a s s i g n a b l e ; template < c l a s s T> struct i s m o v e a s s i g n a b l e ; template < c l a s s T> struct i s d e s t r u c t i b l e ; template < c l a s s T, c l a s s . . . Args> struct is trivially constructible ; template < c l a s s T> struct i s t r i v i a l l y d e f a u l t c o n s t r u c t i b l e ; template < c l a s s T> struct i s t r i v i a l l y c o p y c o n s t r u c t i b l e ; template < c l a s s T> struct i s t r i v i a l l y m o v e c o n s t r u c t i b l e ; template < c l a s s T, c l a s s U> struct i s t r i v i a l l y a s s i g n a b l e ; template < c l a s s T> struct i s t r i v i a l l y c o p y a s s i g n a b l e ; template < c l a s s T> struct i s t r i v i a l l y m o v e a s s i g n a b l e ; template < c l a s s T> struct i s t r i v i a l l y d e s t r u c t i b l e ; template < c l a s s T, c l a s s . . . Args> struct is nothrow constructible ; template < c l a s s T> struct i s n o t h r o w d e f a u l t c o n s t r u c t i b l e ; template < c l a s s T> struct i s n o t h r o w c o p y c o n s t r u c t i b l e ; template < c l a s s T> struct i s n o t h r o w m o v e c o n s t r u c t i b l e ; template < c l a s s T, c l a s s U> struct i s n o t h r o w a s s i g n a b l e ; template < c l a s s T> struct i s n o t h r o w c o p y a s s i g n a b l e ; template < c l a s s T> struct i s n o t h r o w m o v e a s s i g n a b l e ; template < c l a s s T> struct i s n o t h r o w d e s t r u c t i b l e ; template < c l a s s T> struct h a s v i r t u a l d e s t r u c t o r ; // 2 0 . 9 . 5 , t y p e p r o p e r t y q u e r i e s : template < c l a s s T> struct a l i g n m e n t o f ; template < c l a s s T> struct rank ; template < c l a s s T, unsigned I = 0> struct e x t e n t ; // 2 0 . 9 . 6 , t y p e r e l a t i o n s : template < c l a s s T, c l a s s U> struct i s s a m e ; template < c l a s s Base , c l a s s Derived > struct i s b a s e o f ; template < c l a s s From , c l a s s To> struct i s c o n v e r t i b l e ; // 2 0 . 9 . 7 . 1 , c o n s t v o l a t i l e m o d i f i c a t i o n s : template < c l a s s T> struct r e m o v e c o n s t ; template < c l a s s T> struct r e m o v e v o l a t i l e ; template < c l a s s T> struct remove cv ; template < c l a s s T> struct a d d c o n s t ;
84
template < c l a s s T> struct a d d v o l a t i l e ; template < c l a s s T> struct add cv ; // 2 0 . 9 . 7 . 2 , r e f e r e n c e m o d i f i c a t i o n s : template < c l a s s T> struct r e m o v e r e f e r e n c e ; template < c l a s s T> struct a d d l v a l u e r e f e r e n c e ; template < c l a s s T> struct a d d r v a l u e r e f e r e n c e ; // 2 0 . 9 . 7 . 3 , s i g n m o d i f i c a t i o n s : template < c l a s s T> struct ma ke sig ned ; template < c l a s s T> struct make unsigned ; // 2 0 . 9 . 7 . 4 , a r r a y m o d i f i c a t i o n s : template < c l a s s T> struct r e m o v e e x t e n t ; template < c l a s s T> struct r e m o v e a l l e x t e n t s ; // 2 0 . 9 . 7 . 5 , p o i n t e r m o d i f i c a t i o n s : template < c l a s s T> struct r e m o v e p o i n t e r ; template < c l a s s T> struct a d d p o i n t e r ; // 2 0 . 9 . 7 . 6 , o t h e r t r a n s f o r m a t i o n s : template < s t d : : s i z e t Len , s t d : : s i z e t Align > struct aligned storage ; template < s t d : : s i z e t Len , c l a s s . . . Types> struct a l i g n e d u n i o n ; template < c l a s s T> struct decay ; template <bool , c l a s s T = void> struct e n a b l e i f ; template <bool , c l a s s T, c l a s s F> struct c o n d i t i o n a l ; template < c l a s s . . . T> struct common type ; template < c l a s s T> struct u n d e r l y i n g t y p e ; template < c lass > c l a s s r e s u l t o f ; // u n d e f i n e d template < c l a s s F , c l a s s . . . ArgTypes > c l a s s r e s u l t o f <F( ArgTypes . . . ) > ; } // namespace s t d
85
86
template<F lo a t ing Po int Type T> complex <T> a c o s ( const complex <T >&) ; template<F lo a t ing Po int Type T> complex <T> a s i n ( const complex <T >&) ; template<F lo a t ing Po int Type T> complex <T> atan ( const complex <T >&) ; template<F lo a t ing Po int Type T> complex <T> a co sh ( const complex <T >&) ; template<F lo a t ing Po int Type T> complex <T> a s i n h ( const complex <T >&) ; template<F lo a t ing Po int Type T> complex <T> atanh ( const complex <T >&) ; template<F lo a t ing Po int Type T> complex <T> c o s ( const complex <T >&) ; template<F lo a t ing Po int Type T> complex <T> co sh ( const complex <T >&) ; template<F lo a t ing Po int Type T> complex <T> exp ( const complex <T >&) ; template<F lo a t ing Po int Type T> complex <T> l o g ( const complex <T >&) ; template<F lo a t ing Po int Type T> complex <T> l o g 1 0 ( const complex <T >&) ; template< c l a s s T> complex <T> pow ( const complex <T>&, int ) ; template<F lo a t ing Po int Type T> complex <T> pow( const complex <T>&, const T&) ; template<F lo a t ing Po int Type T> complex <T> pow( const complex <T>&, const complex <T>&) ; template<F lo a t ing Po int Type T> complex <T> pow( const T&, const complex <T>&) ; template<F lo a t ing Po int Type T> complex <T> s i n ( const complex <T >&) ; template<F lo a t ing Po int Type T> complex <T> s i n h ( const complex <T >&) ; template<F lo a t ing Po int Type T> complex <T> s q r t ( const complex <T >&) ; template<F lo a t ing Po int Type T> complex <T> tan ( const complex <T >&) ; template<F lo a t ing Po int Type T> complex <T> tanh ( const complex <T >&) ;
87
88
Multiple Associative Container Multiple Hashed Associative Container Multiple Sorted Associative Container Pair Associative Container Random Access Container Reversible Container Sequence Simple Associative Container Sorted Associative Container Unique Associative Container Unique Hashed Associative Container Unique Sorted Associative Container Iterators Bidirectional Iterator Forward Iterator Input Iterator Output Iterator Random Access Iterator Trivial Iterator
89
90
91
92
93
94
95
r e q u i r e s s t d : : F l o a t i n g P o i n t L i k e <l e n g t h t y p e > ; l e n g t h t y p e g e t S i d e ( const P&) ; l e n g t h t y p e g e t H e i g h t ( const P&) ; // . . . } class Dreieck { public : float a ; float b ; float c ; float h a ; float h b ; float h c ; }; c l a s s Pa r a llelo g r a mm { public : double a ; double b ; double h a ; double h b ; }; concept map D r e i e c k L i k e <D r eieck >{ typedef f l o a t l e n g t h t y p e ; f l o a t g e t S i d e ( const D r e i e c k& d ) { return d . a ; } ; f l o a t g e t H e i g h t ( const D r e i e c k& d ) { return d . h a ; } ; }; concept map Pa r a llelo g r a mmL ike <Parallelogramm >{ typedef double l e n g t h t y p e ; double g e t S i d e ( const Pa r a llelo g r a mm& p ) { return p . b ; } ; double g e t H e i g h t ( const Pa r a llelo g r a mm& p ) { return p . h b ; } ; }; template < D r e i e c k L i k e D> D : : l e n g t h t y p e F l a e c h e ( const D& d ) { return 0 . 5 g e t S i d e ( d ) g e t H e i g h t ( d ) ; }; template < Pa r a llelo g r a mmL ik e P> P : : l e n g t h t y p e F l a e c h e ( const P& p ) { return g e t S i d e ( p ) g e t H e i g h t ( p ) ; }; Language Comparison: A Comparative Study of Language Support for Generic Programming
96
97
... static_assert(std::is_assignable<T,T>::value, "T not assignable!"); Vergleiche C++11, Seite 583. ... static_assert(::boost::has_plus_assign< T, iterator_traits<iter>::value_type, T >::value, "no plusassign!"); for (; first != last; ++first) result += *first; return result; } Vergleiche boost::has plus assign. (Alternativ BOOST CONCEPT ASSERT(()), BOOST CONCEPT REQUIRE((())), isbesondere wenn vordenierte CONCEPTs existieren. Mu man eigene CONCEPTs denieren ist der technische Aufwand (Archetypes) eventuell abschreckend.) Ohne BCCL bietet sich die Erstellung eigener Trait-Klassen als Gruppierungsmittel von Sets von Requirements zu Concepts an, die man analog zu Seite 577 des C++11 Standards namespace std { // 20.9.3, helper class: template <class T, T v> struct integral_constant; typedef integral_constant<bool, true> true_type; typedef integral_constant<bool, false> false_type; // 20.9.4.1, primary type categories: template <class T> struct is_void; template <class T> struct is_integral; template <class T> struct is_floating_point; template <class T> struct is_array; template <class T> struct is_pointer; template <class T> struct is_lvalue_reference; template <class T> struct is_rvalue_reference; template <class T> struct is_member_object_pointer; template <class T> struct is_member_function_pointer; template <class T> struct is_enum; template <class T> struct is_union; template <class T> struct is_class; template <class T> struct is_function;
98
// 20.9.4.2, composite type categories: template <class T> struct is_reference; template <class T> struct is_arithmetic; template <class T> struct is_fundamental; template <class T> struct is_object; template <class T> struct is_scalar; template <class T> struct is_compound; template <class T> struct is_member_pointer; // 20.9.4.3, type properties: template <class T> struct is_const; template <class T> struct is_volatile; template <class T> struct is_trivial; template <class T> struct is_trivially_copyable; template <class T> struct is_standard_layout; template <class T> struct is_pod; template <class T> struct is_literal_type; template <class T> struct is_empty; template <class T> struct is_polymorphic; template <class T> struct is_abstract; template <class T> struct is_signed; template <class T> struct is_unsigned; ... template <class T, class U> struct is_assignable; template <class T> struct is_copy_assignable; template <class T> struct is_move_assignable; ... etwa folgendermaen erstellen kann: template<typename I t e r , typename T> struct is summa ble : s t d : : i n t e g r a l c o n s t a n t <bool , NNN: : i s i n p u t i t e r a t o r < I t e r > : : v a l u e && s t d : : i s a s s i g n a b l e <T, T > : : v a l u e && boost : : h a s p l u s a ssi g n < T, i t e r a t o r t r a i t s <i t e r > : : v a l u e t y p e , T > :: v a l u e > {}; Dieses selbserstellte Konzept is summable<.,.> ist dann in einem einzigen static assert() oder sogar zum Concept-basierten Uber laden gem a Abschnitt 1.15.6.2f nutzbar.
99
Aufgabe: Erstellen Sie ein Konzept is input iterator<.> nach diesem Muster gem a Abschnitt 1.15.1.
100
101
102
4 Metaprogrammierung
4.1 Metafunktionen
Metafunktionen (Metaprogrammierung) sind uns schon an diversen Stellen begegnet: promote trait<T1,T2>::T promote in
template <typename T1 , typename T2> typename p r o m o t e t r a i t <T1 , T2 > : : T promote m y f u n c t i o n (T1 x , T2 y ) // { \\... }
stellt den mit T1, T2 assoziierten Typ T promote bereit (vergleiche Abschnitt 1.15.4).
// co u t << Minimum v a l u e f o r i n t : << n u m e r i c l i m i t s <int > : : min ( ) << e n d l ; co u t << Maximum v a l u e f o r i n t : << n u m e r i c l i m i t s <int > : : max ( ) << e n d l ; // co u t << i n t i s s i g n e d : << n u m e r i c l i m i t s <int > : : i s s i g n e d << e n d l ; // co u t << Non s i g n b i t s i n i n t : << n u m e r i c l i m i t s <int > : : d i g i t s << e n d l ; // co u t << i n t has i n f i n i t y : << n u m e r i c l i m i t s <int > : : h a s i n f i n i t y << e n d l ; //
template < c l a s s I n p u t I t e r a t o r > i t e r a t o r t r a i t s <I n p u t I t e r a t o r > : : v a l u e t y p e last value ( InputIterator fi rst , InputIterator last ) { // . . . } greift auf den InputIterator assoziierten value type zu, siehe http://www.sgi.com/tech/stl/iterator traits.html. A metafunction is a construct to map some types or constants to other entities like types, constants, functions, or objects at compile time. The name metafunction comes from fact that they can be regarded as part of a meta-programming language that is evaluated during compilation. (http://trac.seqan.de/wiki/Tutorial/Metafunctions) uhrbaren Datei (Binary) Run time, compile time vs. runtime, mit dem GCC zur ausf
103
104
// n! // C( k , n ) = // k ! ( nk ) ! template < int k , int n> struct Combinations { enum { RET = F a c t o r i a l <n > : :RET/ ( F a c t o r i a l <k > : :RET F a c t o r i a l <nk > : :RET) } ; }; co ut << Combinations < 2 ,4 > ::RET << e n d l ; Templates mit zwei non-type int-Parametern statt eines nicht erlaubten non-type oatParameters: C++ Template Metaprogramming. Siehe auch ldexp() und frexp().
105
Bedingte Typauswahl: // IF template <bool c o n d i t i o n , c l a s s Then , c l a s s Else > struct IF { typedef Then RET; }; template < c l a s s Then , c l a s s Else > struct IF<f a l s e , Then , Else > { typedef E l s e RET; }; // i f s i z e o f ( i n t ) < s i z e o f ( l o n g ) th e n us e l o n g e l s e us e i n t IF< s i z e o f ( int )< s i z e o f ( long ) , long , int > : :RET i ; C++-Metaprogrammierung: template <unsigned int x> struct i d { enum { v a l u e = x } ; }; template <unsigned int x , unsigned int y> struct add { enum { v a l u e = x + y } ; }; // . . . template < int x> struct i d s t a t i c { s t a t i c const int v a l u e = x ; }; template < int x> struct i d s t a t i c c o n s t e x p r { s t a t i c c o n s t e x p r int v a l u e = x ; };
106
4.4 Typfunktionen
Typfunktionen liefern anstelle eines Datenwertes (einer Konstanten) einen oder mehrere Datentypen oder sind von Datentypen abh angig: template < int b i t s > struct number type { typedef int type ; }; template <> struct number type <16> { typedef short type ; }; template <> struct number type <8> { typedef char type ; }; template <typename arg > struct b i t s i z e { enum { v a l u e = s i z e o f ( a r g ) 8 } ; }; template <typename arg > struct b i g g e r t y p e { typedef typename number type < b i t s i z e <arg > : : v a l u e 2 > :: type type ; }; Bedingte Werte: template <bool cond , int t r u e p a r t , int f a l s e p a r t > struct I f T h e n E l s e ; template < int t r u e p a r t , int f a l s e p a r t > struct I f T h e n E l s e <true , t r u e p a r t , f a l s e p a r t > { enum { v a l u e = t r u e p a r t } ; }; template < int t r u e p a r t , int f a l s e p a r t > struct I f T h e n E l s e < f a l s e , t r u e p a r t , f a l s e p a r t > { enum { v a l u e = f a l s e p a r t } ; };
107
108
109
class r ati o { public : typedef r a t i o <num , den> typ e ; s t a t i c c o n s t e x p r i n t m a x t num ; s t a t i c c o n s t e x p r i n t m a x t den ; }; } s t a t i c a s s e r t ( r a t i o a d d < r a t i o < 1,3 > , r a t i o == 1/2 ) ; s t a t i c a s s e r t ( r a t i o a d d < r a t i o < 1,3 > , r a t i o == 1/2 ) ; s t a t i c a s s e r t ( r a t i o m u l t i p l y < r a t i o < 1,3 > , 1/3 3/2 == 1/2 ) ; s t a t i c a s s e r t ( r a t i o m u l t i p l y < r a t i o < 1,3 > , 1/3 3/2 == 1/2 ) ; < 1 ,6 > > ::num == 1 , 1/3+1/6 < 1 ,6 > > ::den == 2 , 1/3+1/6 r a t i o < 3 ,2 > > ::num == 1 , r a t i o < 3 ,2 > > ::den == 2 ,
110
111
return 0 ; } Codedissassembly: Listing: Mit Schleife (dot_product) push ebp mov ebp , esp push edi push esi push ebx mov edi , DWORD PTR [ ebp +8] mov esi , DWORD PTR [ ebp +12] mov ebx , DWORD PTR [ ebp +16] mov ecx , 0 mov edx , 0 cmp ecx , ebx jge L32 L30 : mov eax , DWORD PTR [ edi + edx *4] imul eax , DWORD PTR [esi +edx *4] add ecx , eax inc edx cmp edx , ebx jl L30 L32 : mov eax , ecx pop ebx pop esi pop edi pop ebp ret Listing: Ohne Schleife (dotproduct) push ebp mov ebp , esp push ebx mov edx , DWORD PTR [ ebp +8] mov ebx , DWORD PTR [ ebp +12] mov eax , DWORD PTR [ edx ] imul eax , DWORD PTR [ebx ] mov ecx , DWORD PTR [ edx +4] imul ecx , DWORD PTR [ebx +4] mov edx , DWORD PTR [ edx +8] imul edx , DWORD PTR [ebx +8] add ecx , edx
112
add eax , ecx pop ebx pop ebp ret Sieben Anweisungen statt 18 Anweisungen. (Metaprogrammierung Seite 45.) Endrekursion Tailrekursion
113
C++ Expression templates: Expression templates are a category of C++ template meta programming which delays evaluation of subexpressions until the full expression is known, so that optimizations (especially the elimination of temporaries) can be applied. Zum Beispiel: statt x = a + b + c der Aufruf von Expression<Expression<Array,plus,Array>,plus,Array> mit struct p l u s { s t a t i c int apply ( int a , int b ) { return ( a + b ) ; } }; template < typename L , typename OpTag , typename R > struct E x p r e s s i o n { E x p r e s s i o n (L const& l , R const& r ) : l ( l ) , r ( r ) {} int operator [ ] ( unsigned index ) const { return OpTag : : apply ( l [ index ] , r [ index ] ) ; } L const& l ; R const& r ; }; template< typename L , typename R > Expr essio n <L , plus , R> operator +(L const& l , R const& r ) { return Expr essio n <L , plus , R>( l , r ) ; } ... // v e r z o e g e r t e Aus d ruc k s a us w e rtun g ( l a z y e v a l u a t i o n ) // s o f o r t w i rd nur d e r Parsbaum a u f g e b a u t // b i s z u r A k t i v i e r u n g von o p e r a t o r= template<typename Expr> { Array& Array : : operator =(Expr const& x ) { for ( unsigned i = 0 ; i < this > s i z e ( ) ; ++i ) { ( this ) [ i ] = x [ i ] ; return ( t h i s ) ; } (Metaprogrammierung)
114
Zeit (nicht opt.)[s] 1.776 7.204 17.091 30.305 46.842 85.316 114.167
115
116
typename L i s t : : Head , typename TypeL ist So r t < typename T y p e L i s t A f t e r P i v o t < typename L i s t : : Ta il , typename L i s t : : Head , Comparator > : : R esult , Comparator > : : R e s u l t > > :: R e s u l t R e s u l t ; }; Funktionale Programmierung Lisp Scheme Scala
117
118
Flexibler ist es jedoch, wenn die Programmiersprache Maeinheiten unterst utzt: Units und Dimensions in Fortress:
Vgl.
http://www.ipl.t.u-tokyo.ac.jp/takeichi/attachments/Fortress.pdf
119
Units und Dimensions in der Programmiersprache F# let gravityOnEarth = 9.81<m/s^2> // Beschleunigung let heightOfDrop = 3.5<m> // Laenge let speedOfImpact = sqrt(2.0 * gravityOnEart * heightOfDrop)
C++11 bleibt leider bei den SI-Skalierfaktoren // 2 0 . 1 0 . 6 , c o n v e n i e n c e SI t y p e d e f s typedef r a t i o < 1 , 1000000000000000000000000 > yo ct o ; // s e e b e l o w typedef r a t i o < 1 , 1000000000000000000000 > z e p t o ; // s e e b e l o w typedef r a t i o < 1 , 1000000000000000000 > a t t o ; typedef r a t i o < 1 , 1000000000000000 > femto ; typedef r a t i o < 1 , 1000000000000 > p i c o ; typedef r a t i o < 1 , 1000000000 > nano ; typedef r a t i o < 1 , 1000000 > micro ; typedef r a t i o < 1 , 1000 > m i l l i ; typedef r a t i o < 1 , 100 > c e n t i ; typedef r a t i o < 1 , 10> d e c i ; typedef r a t i o < 1 0 , 1> deca ; typedef r a t i o < 1 0 0 , 1> h e c t o ; typedef r a t i o < 1 0 0 0 , 1> k i l o ; typedef r a t i o < 1 0 0 0 0 0 0 , 1> mega ; typedef r a t i o < 1 0 0 0 0 0 0 0 0 0 , 1> g i g a ; typedef r a t i o < 1 0 0 0 0 0 0 0 0 0 0 0 0 , 1> t e r a ; typedef r a t i o < 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 , 1> pet a ; typedef r a t i o < 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 , 1> exa ; typedef r a t i o < 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 0 00 0 0 , 1> z e t t a ; // s e e b e l o w typedef r a t i o < 1000000000000000000000000 , 1> y o t t a ; // s e e b e l o w stehen, was die Unterst utzung von Maeinheiten angeht.
120
4.10.2 DSLs
In software development and domain engineering, a domain-specic language (DSL) is a programming language or specication language dedicated to a particular problem domain, a particular problem representation technique, and/or a particular solution technique. The concept isnt newspecial-purpose programming languages and all kinds of modeling/specication languages have always existed, but the term has become more popular due to the rise of domain-specic modeling. Scala DSLs DSLs C++ template metaprogramming for DSLs
4.10.3 Ausug in die Domain des technische-wissenschaftlichen Rechnens: Units and Measure in F#
Introducing Units:
[ < Measure > ] type kg [ < Measure > ] type m [ < Measure > ] type s l e t g r a vityO nE a r th = 9.81 <m/ s2> l e t heightOfMyOfficeWindow = 3.5 <m > l e t speedOfImpact = s q r t ( 2 . 0 g r a vityO nE a r th heightOfMyOfficeWindow ) ...
f uhrt zur Compiler-Fehlermeldung The unit measure m does not match the unit measure m/s^2. Unit Conversions:
... let h e i g h t O f M y O f f i c e W i n d o w = 11.5 < ft > let F e e d P e r M e t r e = 3.28084 < ft /m > ... let h e i g h t O f M y O f f i c e W i n d o w I n M e t r e s = h e i g h t O f M y O f f i c e W i n d o w / FeedPerMetre ... type float = float <1 > ...
121
4.10.4 SI-Einheitssystem
Dezimale Vielfache und Teile der SI-Einheiten: Seite 23 Sieben Dimensionen von Megr oen: Seite 9 Basiseinheiten, abgeleitete Einheiten, ...: Seite 18, 19, 20, 21, 24, 27, 29ff.
4.10.5 Boost.Units
Automatische Einheiten-Dimensionsrechnung in C++
# i n c l u d e < complex > # i n c l u d e < iostream > # i n c l u d e < boost / typeof / std / c o m p l e x. hpp > # include # include # include # include # include # include # include < boost / units / s y s t e m s/ si / energy . hpp > < boost / units / s y s t e m s/ si / force . hpp > < boost / units / s y s t e m s/ si / length . hpp > < boost / units / s y s t e m s/ si / e l e c t r i c _ p o t e n t i a l . hpp > < boost / units / s y s t e m s/ si / c u r r e n t. hpp > < boost / units / s y s t e m s/ si / r e s i s t a n c e. hpp > < boost / units / s y s t e m s/ si / io . hpp >
using n a m e s p a c e boost :: units ; using n a m e s p a c e boost :: units :: si ; quantity < energy > work ( const quantity < force >& F , const quantity < length >& dx ) { return F * dx ; // D e f i n e s the r e l a t i o n: work = force * d i s t a n c e. } int main () { // / Test c a l c u l a t i o n of work . quantity < force > F (2.0 * newton ) ; // Define a q u a n t i t y of force . quantity < length > dx (2.0 * meter ) ; // and a distance , quantity < energy > E ( work (F , dx ) ) ; // and c a l c u l a t e the work done . std :: cout << << << << " F = " << F << std :: endl " dx = " << dx << std :: endl " E = " << E << std :: endl std :: endl ;
122
// / Test and check c o m p l e x q u a n t i t i e s. t y p e d e f std :: complex < double > c o m p l e x _ t y p e ; // double real and i m a g i n a r y parts . // Define some c o m p l e x e l e c t r i c a l q u a n t i t i e s. quantity < e l e c t r i c _ p o te nt ia l , complex_type > v = c o m p l e x _ t y p e (12.5 , 0.0) * volts ; quantity < current , complex_type > i = c o m p l e x _ t y p e (3.0 , 4.0) * a m p e r e s; quantity < resistance , complex_type > z = c o m p l e x _ t y p e (1.5 , -2.0) * ohms ; std :: cout << << << // << // << << return 0; } "V = " << v << std :: endl "I = " << i << std :: endl "Z = " << z << std :: endl C a l c u l a t e from Ohm s law v o l t a g e = c u r r e n t * r e s i s t a n c e. " I * Z = " << i * z << std :: endl Check d e f i n e d V is equal to c a l c u l a t e d. " I * Z == V ? " << std :: b o o l a l p h a << ( i * z == v ) << std :: endl std :: endl ;
produziert folgende Ausgabe: F = 2 N dx = 2 m E = 4 J V I Z I*Z I*Z = (12.5,0) V = (3,4) A = (1.5,-2) Ohm = (12.5,0) V == V? true
Conversions
123
Pool von vordefinierten Konstanten alphabetische Liste der Grundeinheiten Meungenauigkeiten und Fehlerfortpflanzung:
quantity < length , measurement < double > > u ( measurement < double >(1.0 ,0.0) * meters ) , w ( measurement < double >(4.52 ,0.02) * meters ) , x ( measurement < double >(2.0 ,0.2) * meters ) , y ( measurement < double >(3.0 ,0.6) * meters ) ; mit den Ergebniswerten (Fehlerbalken): x+y-w w*x x/y ... w*y^2/(u*x)^2 = 10.17(+/-3.52328) m^-1 w/(u*x)^(1/2) = 3.19612(+/-0.160431) dimensionless Dabei wurde die folgende Benutzererweiterung verwendet: // Boost . Units - A C ++ library for zero - overhead d i m e n s i o n a l analysis and // unit / quantity m a n i p u l a t i o n and c o n v e r s i o n // // C o p y r i g h t ( C ) 2003 -2008 Matthias C h r i s t i a n Schabel // C o p y r i g h t ( C ) 2008 Steven Watanabe // // D i s t r i b u t e d under the Boost Software License , Version 1.0. ( See // a c c o m p a n y i n g file L I C E N S E _ 1 _ 0. txt or copy at // http :// www . boost . org / L I C E N S E _ 1 _ 0. txt ) # ifndef B O O S T _ U N I T S _ M E A S U R E M E N T _ H P P # define B O O S T _ U N I T S _ M E A S U R E M E N T _ H P P # include # include # include # include < cmath > < cstdlib > < iomanip > < iostream > = 0.48(+/-0.632772) m = 9.04(+/-0.904885) m^2 = 0.666667(+/-0.149071) dimensionless
# include < boost / io / i o s _ s t a t e. hpp > # include < boost / units / s t a t i c _ r a t i o n a l . hpp > n a m e s p a c e boost {
124
n a m e s p a c e units { n a m e s p a c e s q r _ n a m e s p a c e /* */ { template < class Y > Y sqr ( Y val ) { return val * val ; } } // n a m e s p a c e using s q r _ n a m e s p a c e :: sqr ; template < class Y > class m e a s u r e m e n t { public : typedef measurement <Y > typedef Y
t h i s _ t y p e; v a l u e _ t y p e;
m e a s u r e m e n t( const v a l u e _ t y p e& val = v a l u e _ t y p e () , const v a l u e _ t y p e& err = v a l u e _ t y p e () ) : value_ ( val ) , u n c e r t a i n t y _ ( std :: abs ( err ) ) { } m e a s u r e m e n t( const t h i s _ t y p e& source ) : value_ ( source . value_ ) , u n c e r t a i n t y _ ( source . u n c e r t a i n t y _) { } // ~ m e a s u r e m e n t () { } t h i s _ t y p e& operator =( const t h i s _ t y p e& source ) { if ( this == & source ) return * this ; value_ = source . value_ ; u n c e r t a i n t y _ = source . u n c e r t a i n t y _ ; return * this ; } operator v a l u e _ t y p e () const v a l u e _ t y p e value () const { return value_ ; } { return value_ ; }
125
v a l u e _ t y p e u n c e r t a i n t y () const { return u n c e r t a i n t y _; } v a l u e _ t y p e l o w e r _ b o u n d () const { return value_ u n c e r t a i n t y _; } v a l u e _ t y p e u p p e r _ b o u n d () const { return value_ + u n c e r t a i n t y _; } t h i s _ t y p e& operator +=( const v a l u e _ t y p e& val ) { value_ += val ; return * this ; } t h i s _ t y p e& operator -=( const v a l u e _ t y p e& val ) { value_ -= val ; return * this ; } t h i s _ t y p e& operator *=( const v a l u e _ t y p e& val ) { value_ *= val ; u n c e r t a i n t y _ *= val ; return * this ; } t h i s _ t y p e& operator /=( const v a l u e _ t y p e& val ) { value_ /= val ; u n c e r t a i n t y _ /= val ; return * this ; } t h i s _ t y p e& t h i s _ t y p e& t h i s _ t y p e& t h i s _ t y p e& private : value_type }; } } operator +=( const operator -=( const operator *=( const operator /=( const t h i s _ t y p e& t h i s _ t y p e& t h i s _ t y p e& t h i s _ t y p e& /* source */ ) ; /* source */ ) ; /* source */ ) ; /* source */ ) ;
value_ , u n c e r t a i n t y _;
126
# if B O O S T _ U N I T S _ H A S _ B O O S T _ T Y P E O F B O O S T _ T Y P E O F _ R E G I S T E R _ T E M P L A T E ( boost :: units :: measurement , 1) # endif n a m e s p a c e boost { n a m e s p a c e units { template < class Y > inline measurement <Y >& measurement <Y >:: operator +=( const t h i s _ t y p e& source ) { u n c e r t a i n t y _ = std :: sqrt ( sqr ( u n c e r t a i n t y _) + sqr ( source . uncertainty_)); value_ += source . value_ ; return * this ; } template < class Y > inline measurement <Y >& measurement <Y >:: operator -=( const t h i s _ t y p e& source ) { u n c e r t a i n t y _ = std :: sqrt ( sqr ( u n c e r t a i n t y _) + sqr ( source . uncertainty_)); value_ -= source . value_ ; return * this ; } template < class Y > inline measurement <Y >& measurement <Y >:: operator *=( const t h i s _ t y p e& source ) { u n c e r t a i n t y _ = ( value_ * source . value_ ) * std :: sqrt ( sqr ( u n c e r t a i n t y _/ value_ ) + sqr ( source . u n c e r t a i n t y _/ source . value_ ) ) ; value_ *= source . value_ ; return * this ; }
127
template < class Y > inline measurement <Y >& measurement <Y >:: operator /=( const t h i s _ t y p e& source ) { u n c e r t a i n t y _ = ( value_ / source . value_ ) * std :: sqrt ( sqr ( u n c e r t a i n t y _/ value_ ) + sqr ( source . u n c e r t a i n t y _/ source . value_ ) ) ; value_ /= source . value_ ; return * this ; } // v a l u e _ t y p e op m e a s u r e m e n t template < class Y > inline measurement <Y > operator +( Y lhs , const measurement <Y >& rhs ) { return ( measurement <Y >( lhs , Y (0) ) += rhs ) ; } template < class Y > inline measurement <Y > operator -( Y lhs , const measurement <Y >& rhs ) { return ( measurement <Y >( lhs , Y (0) ) -= rhs ) ; } template < class Y > inline measurement <Y > operator *( Y lhs , const measurement <Y >& rhs ) { return ( measurement <Y >( lhs , Y (0) ) *= rhs ) ; } template < class Y > inline measurement <Y > operator /( Y lhs , const measurement <Y >& rhs ) { return ( measurement <Y >( lhs , Y (0) ) /= rhs ) ; }
128
// m e a s u r e m e n t op v a l u e _ t y p e template < class Y > inline measurement <Y > operator +( const measurement <Y >& lhs , Y rhs ) { return ( measurement <Y >( lhs ) += measurement <Y >( rhs , Y (0) ) ) ; } template < class Y > inline measurement <Y > operator -( const measurement <Y >& lhs , Y rhs ) { return ( measurement <Y >( lhs ) -= measurement <Y >( rhs , Y (0) ) ) ; } template < class Y > inline measurement <Y > operator *( const measurement <Y >& lhs , Y rhs ) { return ( measurement <Y >( lhs ) *= measurement <Y >( rhs , Y (0) ) ) ; } template < class Y > inline measurement <Y > operator /( const measurement <Y >& lhs , Y rhs ) { return ( measurement <Y >( lhs ) /= measurement <Y >( rhs , Y (0) ) ) ; } // m e a s u r e m e n t op m e a s u r e m e n t template < class Y > inline measurement <Y > operator +( const measurement <Y >& lhs , const measurement <Y >& rhs ) { return ( measurement <Y >( lhs ) += rhs ) ; } template < class Y > inline measurement <Y >
129
operator -( const measurement <Y >& lhs , const measurement <Y >& rhs ) { return ( measurement <Y >( lhs ) -= rhs ) ; } template < class Y > inline measurement <Y > operator *( const measurement <Y >& lhs , const measurement <Y >& rhs ) { return ( measurement <Y >( lhs ) *= rhs ) ; } template < class Y > inline measurement <Y > operator /( const measurement <Y >& lhs , const measurement <Y >& rhs ) { return ( measurement <Y >( lhs ) /= rhs ) ; } // / s p e c i a l i z e power typeof helper template < class Y , long N , long D > struct p o w e r _ t y p e of _he lpe r < measurement <Y > , static_rational <N ,D > > { typedef measurement < typename p o w e r _ t y p e of_ hel pe r <Y , static_rational <N ,D > >:: type > type ; static type value ( const measurement <Y >& x ) { const static_rational <N ,D > rat ; const Y m = Y ( rat . n u m e r a t o r () ) / Y ( rat . d e n o m i n a t o r () ) , newval = std :: pow ( x . value () ,m ) , err = newval * std :: sqrt ( std :: pow ( m * x . u n c e r t a i n t y () / x . value () ,2) ) ; return type ( newval , err ) ; } }; // / s p e c i a l i z e root typeof helper template < class Y , long N , long D > struct r o o t _ t y p e of _he lpe r < measurement <Y > , static_rational <N ,D > >
130
{ typedef measurement < typename r o o t _ t y p eo f_h elp er <Y , static_rational <N ,D > >:: type > type ; static type value ( const measurement <Y >& x ) { const static_rational <N ,D > rat ; const Y m = Y ( rat . d e n o m i n a t o r () ) / Y ( rat . n u m e r a t o r () ) , newval = std :: pow ( x . value () ,m ) , err = newval * std :: sqrt ( std :: pow ( m * x . u n c e r t a i n t y () / x . value () ,2) ) ; return type ( newval , err ) ; } }; // stream output template < class Y > inline std :: ostream & operator < <( std :: ostream & os , const measurement <Y >& val ) { boost :: io :: i o s _ p r e c i s i o n _ s a v e r p r e c i s i o n _ s a v e r ( os ) ; boost :: io :: i o s _ f l a g s _ s a v e r f l a g s _ s a v e r( os ) ; os << val . value () << " (+/ - " << val . u n c e r t a i n t y () << " ) " ; return os ; } } // n a m e s p a c e units } // n a m e s p a c e boost # endif // B O O S T _ U N I T S _ M E A S U R E M E N T _ H P P
131
132
Quantities: template < c l a s s T, c l a s s Dimensions > struct q u a n t i t y { e x p l i c i t q u a n t i t y (T x ) : m value ( x ) {} T v a l u e ( ) const { return m private : T m value ; }; ... q u a n t i t y <float , l e n g t h > l ( 1 . 0 f q u a n t i t y <float , mass> m( 2 . 0 f ... m= l; // c o m p i l e time t y p e value ; }
); ); error
Quantity-Arithmetik (value und dimension): add/subtract: template < c l a s s T, c l a s s D> q u a n t i t y <T, D> operator +( q u a n t i t y <T,D> x , q u a n t i t y <T,D> y ) { return q u a n t i t y <T, D>(x . v a l u e ( ) + y . v a l u e ( ) ) ; } template < c l a s s T, c l a s s D> q u a n t i t y <T, D> operator ( q u a n t i t y <T,D> x , q u a n t i t y <T,D> y ) { return q u a n t i t y <T, D>(x . v a l u e ( ) y . v a l u e ( ) ) ; } // . . . q u a n t i t y <float , l e n g t h > l e n 1 ( 1 . 0 f ) ; q u a n t i t y <float , l e n g t h > l e n 2 ( 2 . 0 f ) ; len1 = len1 + len2 ; // OK l e n 1 = l e n 2 + q u a n t i t y <float , mass >( 3 . 7 f ) ; // e r r o r
133
multiplicate:
template < c l a s s T, c l a s s D1 , c l a s s D2> quantity< T , typename mpl : : t r a n s f o r m <D1 , D2 , p l u s f > : : type // new d i m e n s i o n s > operator ( q u a n t i t y <T, D1> x , q u a n t i t y <T, D2> y ) { typedef typename mpl : : t r a n s f o r m <D1 , D2 , p l u s f > : : type dim ; return q u a n t i t y <T, dim >( x . v a l u e ( ) y . v a l u e ( ) ) ; } // mit MPL H i l f e : template < c l a s s OtherDimensions > q u a n t i t y ( q u a n t i t y <T, OtherDimensions > const& r h s ) : m value ( r h s . v a l u e ( ) ) { BOOST STATIC ASSERT ( ( mpl : : equa l <Dimensions , OtherDimensions > : : type : : v a l u e )); }
divide:
template < c l a s s T, c l a s s D1 , c l a s s D2> quantity< T , typename mpl : : t r a n s f o r m <D1 , D2 , mpl : : minus< 1 , 2 > > :: type > operator / ( q u a n t i t y <T, D1> x , q u a n t i t y <T, D2> y ) { typedef typename mpl : : t r a n s f o r m <D1 , D2 , mpl : : minus< 1 , 2 > > :: type dim ; return q u a n t i t y <T, dim >( x . v a l u e ( ) / y . v a l u e ( ) ) ; } MPL-Metafunktionsklasse: The most basic way to formulate a compile-time function so that it can be treated as polymorphic metadata; that is, as a type. A metafunction class is a class with a nested metafunction called apply. Gew ohnungsbed urftige Syntax der Metaprogrammierung: MPL-ManualSeite 99 typedef v e c t o r <int , char , long , short , char , short , double , long> t y p e s ; typedef count <types , short > : : type n ; BOOST MPL ASSERT RELATION( n : : va lue , ==, 2 ) ; (Werte des Metaprogramms werden durch typedefs an Typnamen-Aliases gebunden, ...)
134
135
136
5.2 Policies
Policies bei der Template-Metaprogrammierung: Policies sind Klassen-Templates, die dazu dienen, Verhalten auszulagern. Ein Beispiel: struct M u l t i T h r e a d i n g P o l i c y { typedef / . . . / Mutex ; struct Lock { Lock ( Mutex& mtx ) : mtx ( mtx ) { l o c k ( mtx ) ; } Mutex ( ) { u n l o c k ( mtx ) ; } Mutex& mtx ; }; }; struct S i n g l e T h r e a d i n g P o l i c y { c l a s s Mutex { } ; struct Lock { Lock ( Mutex&) {} Mutex ( ) {} }; }; // // Ein A l g o r i t h m u s k o e n n t e j e t z t so a u s s e h e n : //
137
template< c l a s s T h r e a d i n g P o l i c y > void f ( typename T h r e a d i n g P o l i c y : : Mutex& mtx ) { // . . . i f ( needToTouchThreadSensibleData ( ) ) { typename T h r e a d i n g P o l i c y : : Lock l o c k ( mtx ) ; // l o c k mutex // t h r e a d s a f e s e c t i o n } // . . . } Policies (Implementierungsvarianten/-verhaltensweisen) der STL-Container: (Vergleiche Seite 92) assoziativ/nichtassoziativ sortiert/unsortiert hashed/ohne hash unique/multiple Andere Policies: threadsave errorhandling (exception, errno, ...) allocator (threadsave, singleclient, malloc-based, ...) ... STL Allocators
138
Policy based Design: template < typename o u t p u t p o l i c y , typename l a n g u a g e p o l i c y > c l a s s Hello Wo r ld : public o u t p u t p o l i c y , public l a n g u a g e p o l i c y { using o u t p u t p o l i c y : : P r i n t ; using l a n g u a g e p o l i c y : : Message ; public : // b e h a v i o u r method void Run ( ) { // two p o l i c y methods P r i n t ( Message ( ) ) ; } }; #include < i o s t r e a m > c l a s s Hello Wo r ld O utputP o licy Wr iteTo Co ut { protected : template< typename m e s s a g e t y p e > void P r i n t ( m e s s a g e t y p e message ) { s t d : : co ut << message << s t d : : e n d l ; } }; #include < s t r i n g > class HelloWorld LanguagePolicy English { protected : s t d : : s t r i n g Message ( ) { return H e l l o , World ! ; } }; c l a s s Hello Wo r ld La ng ua g eP o licy Ger ma n { protected : s t d : : s t r i n g Message ( ) { return H a l l o Welt ! ; } }; i nt main ( ) { / example 1 / typedef HelloWorld <Hello Wo r ld O utputP o licy Wr iteTo Co ut ,
139
HelloWorld LanguagePolicy English > my hello wo r ld type ; my hello world type hello world ; h e l l o w o r l d . Run ( ) ; // P r i n t s H e l l o , World ! / example 2 does t h e same b u t u s e s a n o t h e r p o l i c y , t h e l a n g u a g e has chan ged / typedef HelloWorld < Hello Wo r ld O utputP o licy Wr iteTo Co ut , Hello Wo r ld La ng ua g eP o licy Ger ma n > m y o t h e r h e l l o w o r l d t y p e ; my other hello world type hello world2 ; h e l l o w o r l d 2 . Run ( ) ; // P r i n t s H a l l o Welt ! } Seite 8: ThreadingPolicy CreationPolicy Generic Pool Design: CreationPolicy, ExpirationPolicy Boost numeric conversions: OverowhHandler, Float2IntRounder, RawConverter, UserRangeChecker Policies and the STL: AllocationPolicy, CharTPolicy Policy-basiertes Klassendesign, CreationPolicy, Seite 16: CheckingPolicy, ThreadingPolicy
140
141
Nachteile: Schlechte Unterst utzung beim Debuggen, Prolen, ... (m ogliche) Codeexplosion beim Aspekt-Einweben Setzt AOP-Begrie und -Ideologien als Bekannt voraus (dann allerdings leicht erlernbar)) Erfordert Pattern-Matching-Erfahrungen (Filterdenition) Erfordert Recompilation der in der Regel riesigen Unternehmensapplikationen Probleme der Abh angigkeit von der Reihenfolge des Einwebens(?) evtl. schlecht lesbarer neu entstehender Code Sind wirklich alle relevanten Codestellen mit Advices ge andert worden? (fehlende direkte Sprachkonstruckte von C++, z.B. Annotationen mit Aspekt-Bezug, ...) Vorteile: Schnell und einfach aufzusetzen selektiv einsetzbar keine Modikation der Originalquellen n otig leicht entfernbar gute Performance Entwicklungsstand: (siehe Entwicklungsstand der aspektorientierten Programmierung) noch in den Kinderschuhen (erfat unter anderem nur selbst Compiliertes, nicht jedoch lediglich Benutztes, ...) Realisierung des AOP noch unausgereift (Patchlisten, ...) Bis zu akzeptabler Reife d urfte es noch einige Jahre und einige Programmiersprachengenerationen dauern hohe Abstraktion und v ollig andere ungewohnte Herangehensweise stellt hohe Anforderungen an den (zuk unftigen) Entwickler
142