// Boost.TypeErasure library // // Copyright 2011 Steven Watanabe // Copyright 2012 Paul A. Bristow map example // // Distributed under the Boost Software License Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // // from \boost-sandbox\type_erasure\libs\type_erasure\example\print_sequence.cpp // $Id: print_sequence.cpp 78453 2012-05-13 15:24:00Z steven_watanabe $ //[print_sequence /*` (For the source of this example see [@boost:/libs/type_erasure/example/print_sequence.cpp print_sequence.cpp]) This example demonstrates using Boost.TypeErasure to implement a virtual "template" function. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // An uncertain type called measure. #include #include #include #include #include #include using namespace boost::type_erasure; // Placeholders used by the abstract printer during specification of requirements. struct _t : placeholder {}; struct _iter : placeholder {}; struct _os : placeholder {}; // This is more readable than using the 'out of the box' _a, ... _g placeholders. // See placeholder.hpp. template struct base_and_derived { // What does this do??? // Template parameter for concept_interface. // and in list of requirements in abstract printer. // base_and_derived, // _os must derive from std::ios_base? static T& apply(U& arg) { return arg; } }; namespace boost { namespace type_erasure { template struct concept_interface, Base, U> : Base { // Const and non-const versions. operator typename rebind_any::type() const { return call(base_and_derived(), const_cast(*this)); } operator typename rebind_any::type() { return call(base_and_derived(), *this); } }; //namespace std //{ // Works in namespace std but is illegal :-( template std::ostream& operator<< (std::ostream& os, const std::pair& p) { /*! Output a pair of values. \details For example: "1.23 , 3.45". */ os << p.first << ", " << p.second; return os; } // std::ostream& operator<< (std::ostream& os, const std::pair& p) // } //namespace std // Specialized for const std::pair& std::ostream& operator<< (std::ostream& os, const std::pair& p) { /*! Output a pair of values. \details For example: "1.23 , 3.45". */ os << p.first << ", " << p.second; return os; } // std::ostream& operator<< /** * The @ref ostreamable concept allows an @ref any to be * written to a @c std::ostream. template struct ostreamable { static void apply(Os& out, const T& arg) { out << arg; } }; template<> struct ostreamable& > { static void apply(Os& out, const std::pair& arg) { std::cout << arg; outputs correctly! but not how is wanted. } }; */ // Specialize struct ostreamable: template<> struct ostreamable& > { static void apply(Os& out, const std::pair& arg) { out << arg; // No operator<< of type 'Os' } }; } // namespace type_erasure } // namespace boost // Define an abstract sequence printer = a 'template' that is inherited // to implement the examples of actual printers defined below. class abstract_printer { public: // Range must be a Forward Range whose elements can be printed to os. template void print(std::basic_ostream& os, const Range& r) const { // Capture the print arguments. // Range iterators. typename boost::range_iterator::type first(boost::begin(r)), last(boost::end(r)); // Assemble requirements into tuple: ostream, and range pair of iterators. tuple args(os, first, last); // and forward to the real implementation. do_print(get<0>(args), get<1>(args), get<2>(args)); // get<0>() is ostream, get<1>() is first, get<2>() is last. } virtual ~abstract_printer() {} protected: // Define the requirements in an mpl::vector for containers to be printed. typedef boost::mpl::vector< base_and_derived, // _os must derive from std::ios_base. ostreamable<_os, _t>, // type _t must be ostreamable. ostreamable<_os, const char*>, // C string must be ostreamable. forward_iterator<_iter, const _t&>, // t range must have forward iterator. same_type<_t, forward_iterator<_iter, const _t&>::value_type> // _t's type value and iterator must match. > requirements; // Use type_erasure::any to enforce the requirements onto ostream and iterator. typedef boost::type_erasure::any ostream_type; typedef boost::type_erasure::any iterator_type; // Declare the pure virtual function `do_print` that is defined in all real printers. virtual void do_print( ostream_type os, iterator_type first, iterator_type last) const = 0; }; class separator_printer : public abstract_printer { // Output items on same line with a separator like space and/or comma. public: explicit separator_printer(const std::string& sep) : separator(sep) { // Constructor, for example: `separator_printer(", ");` // A separator string must be provided. } protected: // Print all items on one line, separated by the separator argument. 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; // Set by constructor, for example, ", ". }; int main() { separator_printer p1(", "); // Construct a sequence printer with comma separator. std::map my_map; my_map.insert(std::make_pair(1, 9.9)); my_map.insert(std::make_pair(2, 8.8)); my_map.insert(std::make_pair(3, 7.7)); my_map.insert(std::make_pair(4, 6.6)); for (std::map::iterator it = my_map.begin(); it != my_map.end(); ++it) { std::cout << *it << std::endl; } std::cout << std::endl; p1.print(std::cout, my_map); // std::cout << std::endl; // } //] /* Expected Output: Description: Autorun "J:\Cpp\Misc\Debug\type_erasure_print_map.exe" 1, 9.9 2, 8.8 3, 7.7 4, 6.6 1, 9.9, 2, 8.8, 3, 7.7, 4, 6.6 Actual output: type_erasure_print_map.cpp type_erasure_print_map.cpp(132): error C2678: binary '<<' : no operator found which takes a left-hand operand of type 'Os' (or there is no acceptable conversion) type_erasure_print_map.cpp(86): could be 'std::ostream &boost::type_erasure::operator <<(std::ostream &,const std::pair<_Ty1,_Ty2> &)' with [ _Ty1=const int, _Ty2=double ] type_erasure_print_map.cpp(96): or 'std::ostream &boost::type_erasure::operator <<(std::ostream &,const std::pair<_Ty1,_Ty2> &)' with [ _Ty1=const int, _Ty2=double ] while trying to match the argument list '(Os, const std::pair<_Ty1,_Ty2>)' with [ _Ty1=const int, _Ty2=double ] */