Šablony podrobně II: metaprogramování [1. 12.]

Slidy

Odkazy

Úloha na hodině: Mixin

Mixin pro porovnávání pomocí SFINAE a ADL

Implementujte mixin Ord obdobně jako Eq tak že bude platit:

  • třída, která chce Ord využívat z něj zdědí a musí implementovat operator <
  • ostatní operátory se automaticky použijí z Ord
  • každá třída, která využívá Ord zároveň využívá i Eq
comparable.h
namespace comparable {
 
struct Eq { using IsEq = bool; };
 
template< typename T >
auto operator!=( const T &a, const T &b ) -> typename T::IsEq {
    return !(a == b);
}
 
// zde doplňte
}

Testovací main. Všimněte si, že nikde není using namespace comparable; a přesto to funguje (pokud máte správně implementováno).

comparable.cpp
#include "comparable.h"
#include <cassert>
 
struct IntPairEq : comparable::Eq {
    IntPairEq( int x, int y ) : first( x ), second( y ) { }
 
    int first;
    int second;
 
    bool operator==( const IntPairEq &o ) const {
        return first == o.first && second == o.second;
    }
};
 
struct IntPairOrd : comparable::Ord {
    IntPairOrd( int x, int y ) : first( x ), second( y ) { }
 
    int first;
    int second;
};
 
bool operator==( const IntPairOrd &a, const IntPairOrd &b ) {
    return a.first == b.first && a.second == b.second;
}
 
bool operator<( const IntPairOrd &a, const IntPairOrd &b ) {
    return a.first < b.first || (a.first == b.first && a.second < b.second);
}
 
int main() {
    IntPairEq eq1( 0 , 0 );
    IntPairEq eq2( 42, 1 );
 
    IntPairOrd ord1( 0, 0 );
    IntPairOrd ord2( 0, 42 );
 
    assert( eq1 == eq1 );
    assert( !(eq1 == eq2) );
    assert( eq1 != eq2 );
    assert( !(eq1 != eq1) );
 
    assert( ord1 == ord1 );
    assert( ord1 != ord2 );
    assert( ord1 < ord2 );
    assert( ord1 <= ord1 );
    assert( ord1 <= ord2 );
    assert( ord2 > ord1 );
    assert( ord2 >= ord1 );
    assert( ord2 >= ord2 );
    return 0;
}

Úloha na hodině: Fmt

Pokračujte v úloze z minulého týdne, podle instrukcí v .h:

fmt.h
#include <vector>
#include <set>
#include <string>
#include <sstream>
#include <type_traits>
#include <tuple>
 
namespace str {
 
struct Printer {
 
    std::string str() const { return _ss.str(); }
 
 
    Printer &fmt( std::string a ) { _ss << a; return *this; }
 
    // implementujte funkce fmt pro následující případy:
    // - typy splňující std::is_arithmetic (pomocí <<)
    // - n-tice (použijte rekurzi), musí fungovat i pro prázdné ntice
    // - dvojice (pomocí konverze na ntice)
 
    template< typename C >
    Printer &fmtCont( const C &container, std::string lbrace, std::string rbrace ) {
        _ss << lbrace;
        for ( const auto &x : container ) {
            fmt( x );
            _ss << ", ";
        }
        _ss.seekp( -2, std::ios_base::end );
        _ss << rbrace;
        return *this;
    }
 
    template< typename T >
    Printer &fmt( const std::vector< T > &set ) {
        return fmtCont( set, "[ ", " ]" );
    }
 
    template< typename T >
    Printer &fmt( const std::set< T > &set ) {
        return fmtCont( set, "{ ", " }" );
    }
 
  private:
    std::stringstream _ss;
};
 
template< typename T >
std::string fmt( const T &t ) {
    return Printer().fmt( t ).str();
}
 
};

Testovací main:

fmt.cpp
#include "fmt.h"
#include <iostream>
 
int main() {
    std::cout << str::fmt( 1 ) << std::endl;
    std::cout << str::fmt( "ahoj" ) << std::endl;
    std::cout << str::fmt( 1l << 48 ) << std::endl;
    std::cout << str::fmt( std::make_pair( 1, true ) ) << std::endl;
    std::cout << str::fmt( std::vector< int >{ 1, 2, 3 } ) << std::endl;
    std::cout << str::fmt( std::set< int >{ 1, 4, 2 } ) << std::endl;
    std::cout << str::fmt(
        std::vector< std::pair< std::set< int >, std::pair< int, int > > >{
            { { 1, 2, 3 }, { 1, 3 } },
            { { 0, 4, 1, 15 }, { 42, 0 } }
        } ) << std::endl;
    std::cout << str::fmt( std::make_tuple( 1, 2, 3 ) ) << std::endl;
    std::cout << str::fmt(
            std::make_tuple( short( 1 ),
                             1,
                             std::make_tuple(),
                             std::make_tuple( 42L ) )
            ) << std::endl;
}

Vzorový výstup:

1
ahoj
281474976710656
(1, 1)
[ 1, 2, 3 ]
{ 1, 2, 4 }
[ ({ 1, 2, 3 }, (1, 3)), ({ 0, 1, 4, 15 }, (42, 0)) ]
(1, 2, 3)
(1, 1, (), (42))
QR Code
QR Code public:pb173:cviceni_11 (generated for current page)