Šablony podrobně III: metaprogramování [8. 12.]

Slidy

Odkazy

Demo: serializace do stringu

fmt.h
#include <string>
#include <sstream>
#include <type_traits>
#include <tuple>
#include <initializer_list>
#include <cassert>
 
namespace str {
 
struct Printer;
 
template< typename... Args >
Printer &declcheck( Args &&... ) { assert( !"unreachable" ); };
 
struct Printer {
 
    std::string str() const { return _ss.str(); }
 
    // brace enclosed initializer_list does not bind to template
    template< typename T >
    Printer &fmt( std::initializer_list< T > init ) {
        fmtCont( init, '[', ']' );
        return *this;
    }
 
    // overload for anything with begin and end:
    // containers, constant sized arrays
    // this would normally include string literals
    template< typename C >
    auto fmt( const C &cont ) ->
        decltype( declcheck( std::begin( cont ), std::end( cont ) ) )
    {
        return fmtCont( cont, '[', ']' );
    }
 
    // format container with given braces
    template< typename C >
    Printer &fmtCont( const C &container, char lbrace, char rbrace ) {
        // no empty() in initializer list, array[N]
        if ( std::begin( container ) == std::end( container ) ) {
            _ss << lbrace << rbrace;
            return *this;
        }
        _ss << lbrace << " ";
        for ( const auto &x : container ) {
            fmt( x );
            _ss << ", ";
        }
        _ss.seekp( -2, std::ios_base::end );
        _ss << " " << rbrace;
        return *this;
    }
 
    // to we disabled pointers in Printable so we must provide
    // overload for string literals
    Printer &fmt( const char *str ) {
        _ss << str;
        return *this;
    }
 
    // now this is tricky, an overload for anything which is printable,
    // except for things which can decay to pointers (as << for
    // pointers prints address which we don't want)
    // as we don't want to use 2 conditions in declcheck, we encode
    // pointer avoidance in defaulted template parameter
    template< typename Printable,
        typename = typename std::enable_if<
            !std::is_pointer<
                typename std::decay< Printable >::type >::value
            >::type
        >
    auto fmt( const Printable &x ) ->
        decltype( declcheck( std::declval< std::stringstream & >() << x ) )
    {
        _ss << x;
        return *this;
    }
 
    template< typename A, typename B >
    Printer &fmt( const std::pair< A, B > &pair ) {
        return fmt( std::make_tuple( pair.first, pair.second ) );
    }
 
    template< typename... Args >
    Printer &fmt( const std::tuple< Args... > &tuple ) {
        _ss << "(";
        _fmtTuple< 0, sizeof...( Args ) >( tuple );
        _ss << ")";
        return *this;
    }
 
  private:
    std::stringstream _ss;
 
    // all but last element
    template< int I, int E, typename Tuple >
    auto _fmtTuple( const Tuple &t ) ->
        typename std::enable_if< (I < E - 1) >::type
    {
        fmt( std::get< I >( t ) );
        _ss << ", ";
        _fmtTuple< I + 1, E >( t );
    }
 
    // last element
    template< int I, int E, typename Tuple >
    auto _fmtTuple( const Tuple &t ) ->
        typename std::enable_if< I == E - 1 >::type
    {
        fmt( std::get< I >( t ) );
    }
 
    // so that we can handle empty tuples
    template< int I, int E, typename Tuple >
    auto _fmtTuple( const Tuple & ) ->
        typename std::enable_if< (I >= E) >::type
    { }
};
 
// brace-enclosed initializer_list dost not bind to template
template< typename T >
std::string fmt( std::initializer_list< T > init ) {
    return Printer().fmt( std::move( init ) ).str();
}
 
template< typename T >
std::string fmt( const T &t ) {
    return Printer().fmt( t ).str();
}
 
};

Testovací main

fmt.cpp
#include "fmt.h"
#include <iostream>
#include <deque>
#include <vector>
#include <set>
#include <array>
 
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( 1 ) ) << std::endl;
    std::cout << str::fmt( std::make_tuple() ) << std::endl;
    std::cout << str::fmt( std::deque< int >{ 1, 2, 3 } ) << std::endl;
    std::cout << str::fmt( std::vector< int >{} ) << std::endl;
    std::cout << str::fmt( { 1, 2, 3 } ) << std::endl;
 
    int arr[] = { 1, 2, 3 };
    std::cout << str::fmt( arr ) << std::endl;
 
    char carr[] = "test";
    std::cout << str::fmt( carr ) << std::endl;
 
    const char *cptr = "test2";
    std::cout << str::fmt( cptr ) << std::endl;
 
    std::array< int, 3 > sarr{ 42, 42, 42 };
    std::cout << str::fmt( sarr ) << std::endl;
 
    return 0;
}
QR Code
QR Code public:pb173:cviceni_12 (generated for current page)