std variant std variant std variant a polymorphic
















- Slides: 16

std: : variant

std: : variant • std: : variant - a polymorphic type containing one of a fixed set of types • Safe replacement of C unions • plus a data element to remember which type it is using VT = std: : variant< T 0, T 1, T 2>; • More space-effective than a pointer to a dynamically-allocated object with inheritance • If the types are of similar sizes • But not extensible • There is no common interface (base class) required in the types • Allows assignment from any of the types T 0 v 0 = /*. . . */; VT a = v 0; VT b(std: : in_place_type<T 1>, /*. . . */); // VT c(std: : in_place_index<2>, /*. . . */); // b = v 0; // calls T 1: : ~T 1(), T 0: : T 0(v 0) c. emplace<T 1>(/*. . . */); // calls T 2: : ~T 2(), a. emplace<2>(/*. . . */); // calls T 0: : ~T 0(), calls T 1: : T 1(/*. . . */) calls T 2: : T 2(/*. . . */) T 1: : T 1(/*. . . */) T 2: : T 2(/*. . . */) • Access to the contained data: void action( VT & vo) { switch ( vo. index() case 0: { T 0 & v 0 = case 1: { T 1 & v 1 = case 2: { T 2 & v 2 = } ) { std: : get< 0>(vo); v 0. f(); } break; std: : get< 1>(vo); v 1. g(); } break; std: : get< 2>(vo); v 2. h(); } break; 2 NPRG 041 Programová ní v C++ 2019/2020

Storing polymorphic objects Using inheritance T 1 Base useful data Using std: : variant index T 1 useful data T 2 T 3 type info std: : unique_ptr<Base> x = std: : make_unique<T 1>(/*. . . */); • Higher run-time cost • Pointer, dynamic allocation • Extensible set of concrete types std: : variant<T 1, T 2, T 3> x = T 1(/*. . . */); • Lower run-time cost • No dynamic allocation • Always requires maximum space • Not intrusive • Does not use any base class • Fixed set of alternative types 3 NPRG 041 Programmin g in C++ 2019/2020

std: : variant and static visitor using VT = std: : variant< T 0, T 1, T 2>; • std: : visit - Usage through a polymorphic functor struct Visitor. A { void operator()( T 0 & x) { /*. . . */ } void operator()( T 1 & x) { /*. . . */ } void operator()( T 2 & x) { /*. . . */ } }; void action( VT & vo) { Visitor. A va; std: : visit(va, vo); } • It may be used with a polymorphic lambda std: : visit([](auto && a){ a. something(); }, vo); • All the types need a common interface • The interface is not explicitly declared • This is a static equivalent of inheritance and virtual functions • At higher cost – visit requires a tricky implementation similar to visitors • But the memory footprint may still be smaller – no dynamic allocation 4 NPRG 041 Programová ní v C++ 2019/2020

Conversions

Special member functions • Conversion constructors class T { T( U x); }; • Generalized copy constructor • Defines conversion from U to T • If conversion effect is not desired, all one-argument constructors must be "explicit": explicit T( U v); • Conversion operators class T { operator U() const; }; • Defines conversion from T to U • Returns U by value (using copy-constructor of U, if U is a class) • U may be a reference like V& if life-time considerations allow • Compilers will never use more than one user-defined conversion in a chain • The user-defined conversion may be combined with several built-in conversions

Type cast • Various syntax styles (T)e • C-style cast • Inherited from C T(e) • Function-style cast • Equivalent to (T)e • T must be single type identifier or single keyword • Type conversion operators • Differentiated by intent (strength and associated danger) of cast: const_cast<T>(e) static_cast<T>(e) reinterpret_cast<T>(e) • New - run-time assisted cast: dynamic_cast<T>(e)

Const cast const_cast<T>(e) • Suppressing const flags of pointers/references • const U & => U & • const U * => U * • It allows violation of const-ness • In most cases, mutable is a better solution • Example: Counting references to a logically constant object class Data { public: void register_pointer() const { references++; } private: /*. . . data. . . */ mutable int references; };

Static cast static_cast<T>(e) • All implicit conversions • Explicit cast used to enforce the conversion in ambiguous situations • • • Loss-less and lossy number conversions (e. g. int <=> double) Adding const/volatile modifiers to pointers/references Pointer to void* Derived-to-base pointer/reference conversions Invoke any constructor of T capable to accept e • Including copy/move-constructors and explicit constructors • Invoke a conversion operator T() • Some explicit conversions • Anything to void, i. e. discarding the value (e. g. in a conditional expression) • Base-to-derived pointer/reference conversions • No runtime checks, it may produce invalid pointers – use dynamic_cast to check • Integer to an enumeration • May produce undefined results if not mappable • void* to any pointer • No runtime checks possible (even if the object contain type information)

Dynamic cast dynamic_cast<T>(e) • Base-to-derived pointer/reference conversions • Runtime checks included – requires type information in the e object • At least one virtual function required in the type of e • If the dynamic type of e is not T (or derived from T). . . • Pointers: Returns nullptr • References: Throws std: : bad_cast class Base { public: virtual ~Base(); /* base class must have at least one virtual function */ }; class X : public Base { /*. . . */ }; class Y : public Base { /*. . . */ }; Base * p = /*. . . */; X * xp = dynamic_cast< X *>( p); if ( xp ) { /*. . . */ } Y * yp = dynamic_cast< Y *>( p); if ( yp ) { /*. . . */ }

Reinterpret cast reinterpret_cast<T>(e) • Implementation-dependent conversions • • Pointer to integer Integer to pointer Any function-pointer to any function-pointer Any data-pointer to any other data-pointer • No address correction even if pointers are related by inheritance • Any reference to any other reference • Mostly used to read/write binary files/packets/. . . void put_double( std: : ostream & o, const double & d) { o. write( reinterpret_cast< char *>( & d), sizeof( double)); } • The file contents is implementation-dependent – not portable

Templates

Templates • A template is a generic declaration with compile-time formal arguments of these kinds: • any type template< typename T> // also template< class T> • [C++20] the type may be constrained using Concepts • template< • a list of any types (in a variadic template) typename. . . TL> integral number (the actual argument must be a compile-time constant) std: : size_t N> a list of integral numbers (in a variadic template) int. . . NL> another class template (with the given template argument list) template< typename, std: : size_t> class T> a pointer (the actual argument must be an address of a static variable/function) • almost never used, functors work better template< const char * p, inf (*fp)(int, int)> • A function/lambda with auto arguments is also a template

Templates • Class templates • Global classes • Classes nested in other classes, including other class template< typename T, std: : size_t N> class array { /*. . . */ }; // usage: array<double, 3> • Function templates • Global functions • Member functions, including constructors template< typename T> inline T max( T x, T y) { /*. . . */ } // usage: max(p, q) or max<int>(p, q) • Type alias templates [C++11] template< typename T> using array 3 = std: : array< T, 3>; // usage: array 3<double> • Static variable templates [C++14] • Mostly used as global “constants” acting as compile-time functions on types template< typename T> inline constexpr std: : size_t my_sizeof = sizeof(T); // usage: my_sizeof<double>

Templates • Template instantiation • Using the template with particular type and constant parameters • Class, type alias, variable templates: parameters always specified explicitly using my_type = std: : array< int, 10>; using signed_size_t = std: : make_signed_t< std: : size_t>; // std: : ptrdiff_t constexpr bool char_is_signed = std: : is_signed_v<char>; • Function templates: parameters specified explicitly or implicitly • Implicitly - derived by compiler from the types of value arguments int a, b, c; a = max( b, c); // calls max< int> • Explicitly a = max< double>( b, 3. 14); • Mixed: Some (initial) arguments explicitly, the rest implicitly std: : tuple< int, double, int, char, unsigned> v; x = get< 3>( v); // calls std: : get< 3, std: : tuple< int, double, int, char, unsigned>> • Note: Argument-dependent lookup uses both the type arguments in <> and the types of arguments in ()

Templates • Multiple templates with the same name • Class templates: • one "master" template< typename T> class vector {/*. . . */}; • any number of specializations which override the master template • partial specialization template< typename T, std: : size_t n> class unique_ptr< T [n]> {/*. . . */}; • explicit specialization template<> class vector< bool> {/*. . . */}; • Function templates: • • any number of templates with the same name shared with non-templated functions resolved via “argument-dependent-lookup” and “overload resolution” no explicit/partial specialization possible • Instead, the tag-class trick is often used: std: : sort(std: : execution: : par, k. begin(), k. end()); • std: : execution: : par is an (empty) global variable of type std: : execution: : parallel_policy • the type enforces the use of a different (parallel) implementation of std: : sort
Design of assembler in system programming
Monomorphic opinion leader
Polymorphic subprogram
Rails sti vs polymorphic
Polymorphic arguments adalah
The bract is also has zooids
Tiopurine
8086 architecture diagram
Snp variant
Contoh varian dan contoh invariant
Lambda variant
Nrxn duplication
Sigma variant
Fvs variant map
Reported speech present continuous
Loop variant
Variant math