// compile: g++ -std=c++11 metafunctor.cpp #include <iostream> #include <map> // ************************************************************** // **********************TEMPLATE FOR**************************** // ************************************************************** template <template<int> class Func, int... IDs> class ForFunctor; template <template<int> class Func, int ID, int... IDs> class ForFunctor<Func,ID,IDs...> { public: template <typename... Params> static void with(Params& ...params) { Func<ID>::op(params...); ForFunctor<Func,IDs...>::with(params...); } }; template <template<int> class Func> class ForFunctor<Func> { public: template <typename... Params> static void with(Params& ...params) {} }; // ************************************************************** // **********************SOME FUNCTORS**************************** // ************************************************************** template <int ID> class Init { public: template <typename OUT> static void op(OUT& out) { out[ID] = ID; } }; template <int ID> class CopyID { public: template <typename OUT, typename IN> static void op(OUT& out,IN& in) { out[ID] = in[ID]; } }; // ************************************************************** // ***************************MAIN******************************* // ************************************************************** int main() { typedef std::map<int,int> A; A a; A b; ForFunctor<Init,1,2,6,3,10>::with(a); ForFunctor<CopyID,1,2,6>::with(b,a); std::cout << "a: "; for (auto value: a) std::cout << value.second << " "; std::cout << "\nb: "; for (auto value: b) std::cout << value.second << " "; std::cout << "\n"; }
Sunday, December 13, 2015
Varaidic templated template parameters for a loop unroller/code repeater
This basically a demonstration how to use variadic templated template parameter in combination with a variadic template outer handler that locks the typing of the inner part into place with automatic type resolution. This application is basically demonstrating how to create a static loop unroller or code repeater...
Wednesday, April 15, 2015
Creating iomanip for a class - the easy way
Now creating custom io manipulator for your classes can be damn annoying.. The trick to building them is to install and manage a handler for the custom manipulator in the pword array of the ostream. I have hacked this little CustomManip class that allows you to quickly install a lambda function as the a stream manipulator to select from or parameterize the various print methods that you have in play for your class. The only requirement is that each class have at least a " void printDefault(std::ostream& os) const" method that the default print method.
PS: Also there is one little bug with the code.. it does install the streamEvent responder several times.. but what a blog post without a bug or 2..
Anyway heres the code:
The resulting output looks like
PS: Also there is one little bug with the code.. it does install the streamEvent responder several times.. but what a blog post without a bug or 2..
Anyway heres the code:
//g++ -g --std=c++11 custom_class_manip.cpp #include <iostream> #include <ios> #include <sstream> #include <functional> template <typename TYPE> class CustomManip { public: typedef std::function<void(std::ostream&, const TYPE&)> ManipFunc; // installation helper for a manipulator with params class Installer { ManipFunc func_; public: Installer(ManipFunc func) : func_(func) {} inline friend std::ostream& operator<<(std::ostream& os, const Installer& installer ) { CustomManip<TYPE>::install(os, installer.func_); return os; } }; private: struct CustomManipHandle { ManipFunc func_; CustomManipHandle() { std::cout << "new handle at " << this << "\n"; } ~CustomManipHandle() { std::cout << "del handle at " << this << "\n"; } }; static int handleIndex() { // the id for this Custommaniputors params // in the os_base parameter maps static int index = std::ios_base::xalloc(); return index; } public: // for parameterized manipulator installations static Installer make_installer(ManipFunc func) { return Installer(func); } // for unparameterized manipulator installations static void install(std::ostream& os, ManipFunc func) { CustomManipHandle* handle = static_cast<CustomManipHandle*>(os.pword(handleIndex())); // check if its installed on this ostream if (handle == NULL) { // install it handle = new CustomManipHandle(); os.pword(handleIndex()) = handle; // install the callback so we can destroy it os.register_callback (CustomManip<TYPE>::streamEvent,0); } handle->func_ = func; } static void uninstall(std::ios_base& os) { CustomManipHandle* handle = static_cast<CustomManipHandle*>(os.pword(handleIndex())); //delete the installed Custommanipulator handle if (handle != NULL) { os.pword(handleIndex()) = NULL; delete handle; } } static void streamEvent (std::ios::event ev, std::ios_base& os, int id) { switch (ev) { case os.copyfmt_event: std::cout << "copyfmt_event\n"; break; // does this mean i need to copy my manip as well?? case os.imbue_event: std::cout << "imbue_event\n"; break; case os.erase_event: std::cout << "erase_event\n"; uninstall(os); break; } } static void print(std::ostream& os, const TYPE& data) { CustomManipHandle* handle = static_cast<CustomManipHandle*>(os.pword(handleIndex())); if (handle != NULL) { handle->func_(os, data); return; } data.printDefault(os); } }; /********************************** ****************TEST************** **********************************/ class A { int v_; public: A(int v) : v_(v) {} void printDefault(std::ostream& os) const { os << " " << v_ << " default\n"; } void printVer1 (std::ostream& os) const { os << " " << v_ << " abc\n"; } void printVer2 (std::ostream& os) const { os << " " << v_ << " xyz\n"; } void printParam (std::ostream& os, const std::string paramA, const int paramB) const { os << " " << v_ << " param: " << paramA << " " << paramB << "\n"; } }; std::ostream& operator<<(std::ostream& os, const A& a) { CustomManip<A>::print(os, a); return os; } class B { public: void printDefault(std::ostream& os) const { os << " default\n"; } void printVer3 (std::ostream& os) const { os << " mno\n"; } }; std::ostream& operator<<(std::ostream& os, const B& b) { CustomManip<B>::print(os, b); return os; } std::ostream& manip_default (std::ostream& os) { CustomManip<A>::uninstall(os); CustomManip<B>::uninstall(os); return os; } std::ostream& manip_ver1 (std::ostream& os) { CustomManip<A>::install(os, [](std::ostream& oos, const A& a) { a.printVer1(oos); }); return os; } std::ostream& manip_ver2(std::ostream& os) { CustomManip<A>::install(os, [](std::ostream& oos, const A& a) { a.printVer2(oos); }); return os; } std::ostream& manip_ver3(std::ostream& os) { CustomManip<B>::install(os, [](std::ostream& oos, const B& b) { b.printVer3(oos); }); return os; } CustomManip<A>::Installer manip_param(const std::string str, const int other) { return CustomManip<A>::make_installer( [str, other](std::ostream& oos, const A& a) { a.printParam(oos, str, other); }); } int main() { A a(1); B b; std::cout << a << b << "\n"; std::cout << manip_ver1 << a << manip_ver2 << a << manip_ver3 << b << manip_default << a << manip_ver1 << a << manip_param("testing", 4) << a << b << "\n"; std::stringstream oss; oss << manip_ver1 << a << manip_ver2 << a << manip_ver3 << b << manip_default << a << manip_ver1 << a << manip_param("testing", 4) << a << b << "\n"; std::cout << oss.str(); }
The resulting output looks like
1 default default new handle at 0x307de0 1 abc 1 xyz new handle at 0x307e50 mno del handle at 0x307de0 del handle at 0x307e50 1 default new handle at 0x307de0 1 abc 1 param: testing 4 default new handle at 0x307ef0 new handle at 0x307e90 del handle at 0x307ef0 del handle at 0x307e90 new handle at 0x307e90 1 abc 1 xyz mno 1 default 1 abc 1 param: testing 4 default erase_event del handle at 0x307e90 erase_event erase_event
Subscribe to:
Posts (Atom)