![]() |
![]() ![]() ![]() ![]() ![]() |
![]() |
ExamplesBoost , The Boost C++ Libraries BoostBook Documentation Subset , Chapter 37. Boost.TypeErasure
|
![]() | 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 |
---|---|
В этом примере используются функции 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 }); }
Статья Examples раздела The Boost C++ Libraries BoostBook Documentation Subset Chapter 37. Boost.TypeErasure может быть полезна для разработчиков на c++ и boost.
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.
:: Главная :: Chapter 37. Boost.TypeErasure ::
реклама |