Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
Разработка программного обеспечения

Examples

Boost , The Boost C++ Libraries BoostBook Documentation Subset , Chapter 37. Boost.TypeErasure

Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

PrevUpHomeNext

(Источник этого примера см.print_sequence.cpp)

Этот пример определяет иерархию классов, которая позволяет форматировать последовательность несколькими различными способами. Мы хотели бы иметь возможность обрабатывать любую последовательность и любой тип потока, поскольку форматирование диапазона не зависит от форматирования отдельных элементов. Таким образом, наш интерфейс должен выглядеть примерно так:

class abstract_printer {
public:
    template<class CharT, class Traits, class Range>
    virtual void print(std::basic_ostream<CharT, Traits>& os, const Range& r) const = 0;
};

К сожалению, это незаконно, потому что виртуальная функция не может быть шаблоном. Тем не менее, мы можем определить класс с таким же поведением, используя Boost. Типовое удаление.

#include <boost/type_erasure/any.hpp>
#include <boost/type_erasure/iterator.hpp>
#include <boost/type_erasure/operators.hpp>
#include <boost/type_erasure/tuple.hpp>
#include <boost/type_erasure/same_type.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/iterator.hpp>
#include <iostream>
#include <iomanip>
#include <vector>
using namespace boost::type_erasure;
struct _t : placeholder {};
struct _iter : placeholder {};
struct _os : placeholder {};
template<class T, class U = _self>
struct base_and_derived
{
    static T& apply(U& arg) { return arg; }
};
namespace boost {
namespace type_erasure {
template<class T, class U, class Base>
struct concept_interface<base_and_derived<T, U>, Base, U> : Base
{
    operator typename rebind_any<Base, const T&>::type() const
    {
        return call(base_and_derived<T, U>(), const_cast<concept_interface&>(*this));
    }
    operator typename rebind_any<Base, T&>::type()
    {
        return call(base_and_derived<T, U>(), *this);
    }
};
}
}
// abstract_printer - An abstract base class for formatting sequences.
class abstract_printer {
public:
    // print - write a sequence to a std::ostream in a manner
    //   specific to the derived class.
    //
    // Requires: Range must be a Forward Range whose elements can be
    //   printed to os.
    template<class CharT, class Traits, class Range>
    void print(std::basic_ostream<CharT, Traits>& os, const Range& r) const {
        // Capture the arguments
        typename boost::range_iterator<const Range>::type
            first(boost::begin(r)),
            last(boost::end(r));
        tuple<requirements, _os&, _iter, _iter> args(os, first, last);
        // and forward to the real implementation
        do_print(get<0>(args), get<1>(args), get<2>(args));
    }
    virtual ~abstract_printer() {}
protected:
    // define the concept requirements of the arguments of
    // print and typedef the any types.
    typedef boost::mpl::vector<
        base_and_derived<std::ios_base, _os>,
        ostreamable<_os, _t>,
        ostreamable<_os, const char*>,
        forward_iterator<_iter, const _t&>,
        same_type<_t, forward_iterator<_iter, const _t&>::value_type>
    > requirements;
    typedef boost::type_erasure::any<requirements, _os&> ostream_type;
    typedef boost::type_erasure::any<requirements, _iter> iterator_type;
    // do_print - This method must be implemented by derived classes
    virtual void do_print(
        ostream_type os, iterator_type first, iterator_type last) const = 0;
};
// separator_printer - writes the elements of a sequence
//   separated by a fixed string.  For example, if
//   the separator is ", " separator_printer produces
//   a comma separated list.
class separator_printer : public abstract_printer {
public:
    explicit separator_printer(const std::string& sep) : separator(sep) {}
protected:
    virtual void do_print(
        ostream_type os, iterator_type first, iterator_type last) const {
        if(first != last) {
            os << *first;
            ++first;
            for(; first != last; ++first) {
                os << separator.c_str() << *first;
            }
        }
    }
private:
    std::string separator;
};
// column_separator_printer - like separator_printer, but
//   also inserts a line break after every n elements.
class column_separator_printer : public abstract_printer {
public:
    column_separator_printer(const std::string& sep, std::size_t num_columns)
      : separator(sep),
        cols(num_columns)
    {}
protected:
    virtual void do_print(
        ostream_type os, iterator_type first, iterator_type last) const {
        std::size_t count = 0;
        for(; first != last; ++first) {
            os << *first;
            boost::type_erasure::any<requirements, _iter> temp = first;
            ++temp;
            if(temp != last) {
                os << separator.c_str();
            }
            if(++count % cols == 0) {
                os << "\n";
            }
        }
    }
private:
    std::string separator;
    std::size_t cols;
};
// aligned_column_printer - formats a sequence in columns
//   reading down.  For example, given the sequence
//   { 1, 2, 3, 4, 5 }, aligned_column_printer might print
//   1   4
//   2   5
//   3
class aligned_column_printer : public abstract_printer {
public:
    aligned_column_printer(std::size_t column_width, std::size_t num_columns)
      : width(column_width),
        cols(num_columns)
    {}
protected:
    virtual void do_print(
        ostream_type os, iterator_type first, iterator_type last) const
    {
        if(first == last) return;
        std::vector<iterator_type> column_iterators;
        // find the tops of the columns
        std::size_t count = 0;
        for(iterator_type iter = first; iter != last; ++iter) {
            ++count;
        }
        std::size_t rows = (count + cols - 1) / cols;
        count = 0;
        for(iterator_type iter = first; iter != last; ++iter) {
            if(count % rows == 0) {
                column_iterators.push_back(iter);
            }
            ++count;
        }
        iterator_type last_col = column_iterators.back();
        // print the full rows
        while(column_iterators.back() != last) {
            for(std::vector<iterator_type>::iterator
                iter = column_iterators.begin(),
                end = column_iterators.end(); iter != end; ++iter)
            {
                static_cast<std::ios_base&>(os).width(width);
                os << **iter;
                ++*iter;
            }
            os << "\n";
        }
        // print the rows that are missing the last column
        column_iterators.pop_back();
        if(!column_iterators.empty()) {
            while(column_iterators.back() != last_col) {
                for(std::vector<iterator_type>::iterator
                    iter = column_iterators.begin(),
                    end = column_iterators.end(); iter != end; ++iter)
                {
                    static_cast<std::ios_base&>(os).width(width);
                    os << **iter;
                    ++*iter;
                }
                os << "\n";
            }
        }
    }
private:
    std::size_t width;
    std::size_t cols;
};
int main() {
    int test[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    separator_printer p1(",");
    p1.print(std::cout, test);
    std::cout << std::endl;
    column_separator_printer p2(",", 4);
    p2.print(std::cout, test);
    std::cout << std::endl;
    aligned_column_printer p3(16, 4);
    p3.print(std::cout, test);
}

(Источник этого примера см.printf.cpp)

В этом примере используется библиотека для реализации безопасного типа printf.

[Note]Note

В этом примере используются функции C++11. Вам понадобится недавний компилятор для работы.

#include <boost/type_erasure/builtin.hpp>
#include <boost/type_erasure/operators.hpp>
#include <boost/type_erasure/any_cast.hpp>
#include <boost/type_erasure/any.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/io/ios_state.hpp>
#include <iostream>
#include <sstream>
#include <iomanip>
#include <vector>
#include <string>
namespace mpl = boost::mpl;
using namespace boost::type_erasure;
using namespace boost::io;
// We capture the arguments by reference and require nothing
// except that each one must provide a stream insertion operator.
typedef any<
    mpl::vector<
        typeid_<>,
        ostreamable<>
    >,
    const _self&
> any_printable;
typedef std::vector<any_printable> print_storage;
// Forward declaration of the implementation function
void print_impl(std::ostream& os, const char * format, const print_storage& args);
// print
//
// Writes values to a stream like the classic C printf function.  The
// arguments are formatted based on specifiers in the format string,
// which match the pattern:
//
// '%' [ argument-number '$' ] flags * [ width ] [ '.' precision ] [ type-code ] format-specifier
//
// Other characters in the format string are written to the stream unchanged.
// In addition the sequence, "%%" can be used to print a literal '%' character.
// Each component is explained in detail below
//
// argument-number:
//   The value must be between 1 and sizeof... T.  It indicates the
//   index of the argument to be formatted.  If no index is specified
//   the arguments will be processed sequentially.  If an index is
//   specified for one argument, then it must be specified for every argument.
//
// flags:
//   Consists of zero or more of the following:
//   '-': Left justify the argument
//   '+': Print a plus sign for positive integers
//   '0': Use leading 0's to pad instead of filling with spaces.
//   ' ': If the value doesn't begin with a sign, prepend a space
//   '#': Print 0x or 0 for hexadecimal and octal numbers.
//
// width:
//   Indicates the minimum width to print.  This can be either
//   an integer or a '*'.  an asterisk means to read the next
//   argument (which must have type int) as the width.
//
// precision:
//   For numeric arguments, indicates the number of digits to print.  For
//   strings (%s) the precision indicates the maximum number of characters
//   to print.  Longer strings will be truncated.  As with width
//   this can be either an integer or a '*'.  an asterisk means
//   to read the next argument (which must have type int) as
//   the width.  If both the width and the precision are specified
//   as '*', the width is read first.
//
// type-code:
//   This is ignored, but provided for compatibility with C printf.
//
// format-specifier:
//   Must be one of the following characters:
//   d, i, u: The argument is formatted as a decimal integer
//   o:       The argument is formatted as an octal integer
//   x, X:    The argument is formatted as a hexadecimal integer
//   p:       The argument is formatted as a pointer
//   f:       The argument is formatted as a fixed point decimal
//   e, E:    The argument is formatted in exponential notation
//   g, G:    The argument is formatted as either fixed point or using
//            scientific notation depending on its magnitude
//   c:       The argument is formatted as a character
//   s:       The argument is formatted as a string
//
template<class... T>
void print(std::ostream& os, const char * format, const T&... t)
{
    // capture the arguments
    print_storage args = { any_printable(t)... };
    // and forward to the real implementation
    print_impl(os, format, args);
}
// This overload of print with no explicit stream writes to std::cout.
template<class... T>
void print(const char * format, const T&... t)
{
    print(std::cout, format, t...);
}
// The implementation from here on can be separately compiled.
// utility function to parse an integer
int parse_int(const char *& format) {
    int result = 0;
    while(char ch = *format) {
        switch(ch) {
        case '0': case '1': case '2': case '3': case '4':
        case '5': case '6': case '7': case '8': case '9':
            result = result * 10 + (ch - '0');
            break;
        default: return result;
        }
        ++format;
    }
    return result;
}
// printf implementation
void print_impl(std::ostream& os, const char * format, const print_storage& args) {
    int idx = 0;
    ios_flags_saver savef_outer(os, std::ios_base::dec);
    bool has_positional = false;
    bool has_indexed = false;
    while(char ch = *format++) {
        if (ch == '%') {
            if (*format == '%') { os << '%'; continue; }
            ios_flags_saver savef(os);
            ios_precision_saver savep(os);
            ios_fill_saver savefill(os);
            int precision = 0;
            bool pad_space = false;
            bool pad_zero = false;
            // parse argument index
            if (*format != '0') {
                int i = parse_int(format);
                if (i != 0) {
                    if(*format == '$') {
                        idx = i - 1;
                        has_indexed = true;
                        ++format;
                    } else {
                        os << std::setw(i);
                        has_positional = true;
                        goto parse_precision;
                    }
                } else {
                    has_positional = true;
                }
            } else {
                has_positional = true;
            }
            // Parse format modifiers
            while((ch = *format)) {
                switch(ch) {
                case '-': os << std::left; break;
                case '+': os << std::showpos; break;
                case '0': pad_zero = true; break;
                case ' ': pad_space = true; break;
                case '#': os << std::showpoint << std::showbase; break;
                default: goto parse_width;
                }
                ++format;
            }
        parse_width:
            int width;
            if (*format == '*') {
                ++format;
                width = any_cast<int>(args.at(idx++));
            } else {
                width = parse_int(format);
            }
            os << std::setw(width);
        parse_precision:
            if (*format == '.') {
                ++format;
                if (*format == '*') {
                    ++format;
                    precision = any_cast<int>(args.at(idx++));
                } else {
                    precision = parse_int(format);
                }
                os << std::setprecision(precision);
            }
            // parse (and ignore) the type modifier
            switch(*format) {
            case 'h': ++format; if(*format == 'h') ++format; break;
            case 'l': ++format; if(*format == 'l') ++format; break;
            case 'j':
            case 'L':
            case 'q':
            case 't':
            case 'z':
                ++format; break;
            }
            std::size_t truncate = 0;
            // parse the format code
            switch(*format++) {
            case 'd': case 'i': case 'u': os << std::dec; break;
            case 'o': os << std::oct; break;
            case 'p': case 'x': os << std::hex; break;
            case 'X': os << std::uppercase << std::hex; break;
            case 'f': os << std::fixed; break;
            case 'e': os << std::scientific; break;
            case 'E': os << std::uppercase << std::scientific; break;
            case 'g': break;
            case 'G': os << std::uppercase; break;
            case 'c': case 'C': break;
            case 's': case 'S': truncate = precision; os << std::setprecision(6); break;
            default: assert(!"Bad format string");
            }
            if (pad_zero && !(os.flags() & std::ios_base::left)) {
                os << std::setfill('0') << std::internal;
                pad_space = false;
            }
            if (truncate != 0 || pad_space) {
                // These can't be handled by std::setw.  Write to a stringstream and
                // pad/truncate manually.
                std::ostringstream oss;
                oss.copyfmt(os);
                oss << args.at(idx++);
                std::string data = oss.str();
                if (pad_space) {
                    if (data.empty() || (data[0] != '+' && data[0] != '-' && data[0] != ' ')) {
                        os << ' ';
                    }
                }
                if (truncate != 0 && data.size() > truncate) {
                    data.resize(truncate);
                }
                os << data;
            } else {
                os << args.at(idx++);
            }
            // we can't have both positional and indexed arguments in
            // the format string.
            assert(has_positional ^ has_indexed);
        } else {
            std::cout << ch;
        }
    }
}
int main() {
    print("int: %d\n", 10);
    print("int: %0#8X\n", 0xA56E);
    print("double: %g\n", 3.14159265358979323846);
    print("double: %f\n", 3.14159265358979323846);
    print("double: %+20.9e\n", 3.14159265358979323846);
    print("double: %0+20.9g\n", 3.14159265358979323846);
    print("double: %*.*g\n", 20, 5, 3.14159265358979323846);
    print("string: %.10s\n", "Hello World!");
    print("double: %2$*.*g int: %1$d\n", 10, 20, 5, 3.14159265358979323846);
}

(Источник этого примера см.multifunction.cpp)

В этом примере реализовано расширение Boost. Функция, поддерживающая несколько подписей.

[Note]Note

В этом примере используются функции C++11. Вам понадобится недавний компилятор для работы.

#include <boost/type_erasure/any.hpp>
#include <boost/type_erasure/builtin.hpp>
#include <boost/type_erasure/callable.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/variant.hpp>
#include <boost/phoenix/core.hpp>
#include <boost/phoenix/operator.hpp>
#include <boost/range/algorithm.hpp>
#include <algorithm>
#include <vector>
#include <string>
#include <iostream>
namespace mpl = boost::mpl;
using namespace boost::type_erasure;
namespace phoenix = boost::phoenix;
// First of all we'll declare the multifunction template.
// multifunction is like Boost.Function but instead of
// taking one signature, it takes any number of them.
template<class... Sig>
using multifunction =
    any<
        mpl::vector<
            copy_constructible<>,
            typeid_<>,
            relaxed,
            callable<Sig>...
        >
    >;
// Let's use multifunction to process a variant.  We'll start
// by defining a simple recursive variant to use.
typedef boost::make_recursive_variant<
    int,
    double,
    std::string,
    std::vector<boost::recursive_variant_> >::type variant_type;
typedef std::vector<variant_type> vector_type;
// Now we'll define a multifunction that can operate
// on the leaf nodes of the variant.
typedef multifunction<void(int), void(double), void(std::string)> function_type;
class variant_handler
{
public:
    void handle(const variant_type& arg)
    {
        boost::apply_visitor(impl, arg);
    }
    void set_handler(function_type f)
    {
        impl.f = f;
    }
private:
    // A class that works with boost::apply_visitor
    struct dispatcher : boost::static_visitor<void>
    {
        // used for the leaves
        template<class T>
        void operator()(const T& t) { f(t); }
        // For a vector, we recursively operate on the elements
        void operator()(const vector_type& v)
        {
            boost::for_each(v, boost::apply_visitor(*this));
        }
        function_type f;
    };
    dispatcher impl;
};
int main() {
    variant_handler x;
    x.set_handler(std::cout << phoenix::val("Value: ") << phoenix::placeholders::_1 << std::endl);
    x.handle(1);
    x.handle(2.718);
    x.handle("The quick brown fox jumps over the lazy dog.");
    x.handle(vector_type{ 1.618, "Gallia est omnis divisa in partes tres", 42 });
}


PrevUpHomeNext

Статья Examples раздела The Boost C++ Libraries BoostBook Documentation Subset Chapter 37. Boost.TypeErasure может быть полезна для разработчиков на c++ и boost.




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.



:: Главная :: Chapter 37. Boost.TypeErasure ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-08-30 11:47:00
2025-05-19 17:41:37/0.032603979110718/1