Serving the Quantitative Finance Community

 
User avatar
DevonFangs
Topic Author
Posts: 0
Joined: November 9th, 2009, 1:49 pm

Pure virtual functor

March 21st, 2012, 8:33 pm

QuoteOriginally posted by: PolterQuoteOriginally posted by: DevonFangsQuoteOriginally posted by: PolterWhy not use std::function (or boost::function) and composition instead of pure virtual for "func" and inheritance? // I guess that's what you considered as #2 idea.Can you show an example use case, e.g., what do you want to do with your Accumulator once you have it?Derive from it (implementing its "func" along the way) and use along the way of DerivedAccumulator derived_accumulator(some_vector); derived_accumulator.accum(); ?Alternatively, consider passing the function-pointer as a template argument: http://ideone.com/OAyeGint triple(int y) {return 3*y;} template <int (*func)(int)>struct myclass { int operator()(int x, int y) {return x + func(y);}};int triple(int y) {return 3*y;}int main(){ myclass<triple> myobject; std::cout << std::accumulate (numbers, numbers+3, init, myobject );}Yes, with composition I meant that and yes, the usage is exactly as you intended it.I also considered the template way, but I'm under some constraints. I'm writing monkey code which must:i) avoid templateii) better no boostiii) easy to use: so the guy taking my interface only has to write a class with the implementation of func.I know, it's depressing but SOMEHOW stimulating.Ah, I see your point (and I feel you regarding the constraints).At the same time, from the (iii) (ease-of-use) point of view, I think this solution (Boost.Range & Boost.Phoenix) is unbeatable: double accumulation_result = boost::accumulate(numbers, init, arg1 + arg2*arg2);Notice a few things:- no user-written templates - no pointers- no inheritance, no OOP -- if your functions are as simple as this (sum-of-squares with an initial-value) you can throw this at a newbie who came from a procedural/imperative programming, tell him that "arg" is an argument and be done with explaining things; I sincerely believe that classes/OOP/inheritance/pointers combination that is shown as an alternative has a potential for poisonous complexity and would much rather recommend showing a newbie a copy-paste of #includes pointing to boost libs than explaining the subtleties of the interactions in the classes/OOP/inheritance/pointers combination -- and I think extensibility is beautiful in this context ("just hack with this line of code" instead of "create a function object, pass it by pointer to this wrapper class over there, make sure you inherit like that, etc."). It is easier.This is the complete source code: http://ideone.com/IHx56Still, if you insist on function objects, it's still easy with Boost.Range & Boost.Phoenix: double accumulation_result = boost::accumulate(numbers, init, arg1 + func(arg2));Full source code: http://ideone.com/yeNXyNotice that there are no function pointers or inheritance (which should be a plus for a newbie), but the magic "template" keyword has appeared. However, there's a handy wrapper boost:hoenix::function -- which again appears "easy" to the end-user: so, depends on how much control you have over the situation, perhaps you can just expose a bunch of wrappers?What is nice about going with Boost.Phoenix is that it understands cmath functions (so if your "func" is something from cmath, you don't have to do anything, just #include, compile and run): http://ideone.com/WqJNuFor instance, for the square-root function: double accumulation_result = boost::accumulate(numbers, init, arg1 + boost:hoenix::sqrt(arg2));Naturally, you can hide the fully-qualified names like boost:hoenix::arg_names::arg1 or boost:hoenix::sqrt from the end-user by the appropriate using declaration (or even using namespace directive) if your goal is to "hide" the fact that we're using Boost (i.e., to make this appear "easy" to the end-user).If you do that, then in terms of extensibility going from squares to square roots means going from this: double accumulation_result = accumulate(numbers, init, arg1 + arg2*arg2);to this: double accumulation_result = accumulate(numbers, init, arg1 + sqrt(arg2));I honestly believe this cannot be made any simpler by introducing stuff like pointers, OOP and inheritance. Locality is very important -- my experience is that rookies aren't good at thinking at multiple abstraction levels or even multiple code levels (i.e., if they have to scroll up / jump to another file then IT'S TOO HARD). That's exactly the kind of complexity you may introduce if you go for the OOP/ptrs/inheritance approach. I don't believe you'll gain anything by this -- if anything, you'll only make the life of your code monkey harder ;-)This is absolutely great, thanks. I'll go through this carefully. And I'll let you know what the monkey says
 
User avatar
CrazyClimber

Pure virtual functor

March 21st, 2012, 8:44 pm

If this is a one time calculation, then you should store a const reference to the vector in the class, otherwise you are doing a copy every time. If you are keeping the Accumulator object around for some time (for some reason), then I guess you should do a copy. I'm not sure why you'd need to do that. If you were going to call accum() more than once, then you'd probably want to store the result of the first time it's called, or just do all the calculations when the object is instantiated, then accum() would simply return that value.
 
User avatar
bojan
Posts: 0
Joined: August 8th, 2008, 5:35 am

Pure virtual functor

March 21st, 2012, 10:07 pm

Excessive copies is reckognised as one problem in some std:: algorithms. In fact the boost::ref library was written precisely to address this problem in some cases. In your case you would need to use both boost::ref and boost::bind, so that is breaking your constraints, but if you are interested this is the way to do it. If you want to truly stick to your constraints I would recommend writing out the std::accumulate function by hand for your case.
 
User avatar
Cuchulainn
Posts: 22933
Joined: July 16th, 2004, 7:38 am

Pure virtual functor

March 22nd, 2012, 7:42 am

QuoteOriginally posted by: bojanExcessive copies is reckognised as one problem in some std:: algorithms. In fact the boost::ref library was written precisely to address this problem in some cases. In your case you would need to use both boost::ref and boost::bind, so that is breaking your constraints, but if you are interested this is the way to do it. If you want to truly stick to your constraints I would recommend writing out the std::accumulate function by hand for your case.What about the Boost bind overhead as well? Or a lambda, which should be more efficient? random discussion
Last edited by Cuchulainn on March 21st, 2012, 11:00 pm, edited 1 time in total.
 
User avatar
DevonFangs
Topic Author
Posts: 0
Joined: November 9th, 2009, 1:49 pm

Pure virtual functor

March 22nd, 2012, 8:39 am

QuoteOriginally posted by: bojanExcessive copies is reckognised as one problem in some std:: algorithms. In fact the boost::ref library was written precisely to address this problem in some cases. In your case you would need to use both boost::ref and boost::bind, so that is breaking your constraints, but if you are interested this is the way to do it. If you want to truly stick to your constraints I would recommend writing out the std::accumulate function by hand for your case.Thanks bojan good to know, I like this. When implementing the subclass one does not necessarily know the details of how the object is passed to accumulate.
Last edited by DevonFangs on March 21st, 2012, 11:00 pm, edited 1 time in total.
 
User avatar
katastrofa
Posts: 7931
Joined: August 16th, 2007, 5:36 am
Location: Event Horizon

Pure virtual functor

March 22nd, 2012, 9:06 am

QuoteOriginally posted by: DevonFangsQuoteOriginally posted by: katastrofaSimple wrapper (the code may or may not work, but it's enough to convey the idea):Thanks K, it did it. I don't like it, but it did it In defence of my solution, it's much less lines of code than the other solutions posted (you can easily turn it into a template or reuse it). If you had just one parameter to pass to the virtual function, you could just use std::mem_fun_ref, IMHO.
 
User avatar
DevonFangs
Topic Author
Posts: 0
Joined: November 9th, 2009, 1:49 pm

Pure virtual functor

March 22nd, 2012, 9:08 am

QuoteOriginally posted by: katastrofaQuoteOriginally posted by: DevonFangsQuoteOriginally posted by: katastrofaSimple wrapper (the code may or may not work, but it's enough to convey the idea):Thanks K, it did it. I don't like it, but it did it In defence of my solution, it's much less lines of code than the other solutions posted (you can easily turn it into a template or reuse it). If you had just one parameter to pass to the virtual function, you could just use std::mem_fun_ref, IMHO.Thanks. Don't take it personally, I have a perverse taste when it come to code
Last edited by DevonFangs on March 21st, 2012, 11:00 pm, edited 1 time in total.
 
User avatar
Cuchulainn
Posts: 22933
Joined: July 16th, 2004, 7:38 am

Pure virtual functor

March 22nd, 2012, 11:51 am

QuoteOriginally posted by: DevonFangsQuoteOriginally posted by: katastrofaQuoteOriginally posted by: DevonFangsQuoteOriginally posted by: katastrofaSimple wrapper (the code may or may not work, but it's enough to convey the idea):Thanks K, it did it. I don't like it, but it did it In defence of my solution, it's much less lines of code than the other solutions posted (you can easily turn it into a template or reuse it). If you had just one parameter to pass to the virtual function, you could just use std::mem_fun_ref, IMHO.Thanks. Don't take it personally, I have a perverse taste when it come to code I would not worry about it. There are many programming Babylonic 'styles' out there Try getting GP and OOP talking together. LOL
Last edited by Cuchulainn on March 21st, 2012, 11:00 pm, edited 1 time in total.
 
User avatar
Polter
Posts: 1
Joined: April 29th, 2008, 4:55 pm

Pure virtual functor

March 6th, 2013, 12:50 am

QuoteWhy not use std::function (or boost::function) . . . instead of pure virtual . . . and inheritance?Continuing, now with C++11:http://isocpp.org/blog/2013/03/the-impo ... e-skarupke
 
User avatar
Cuchulainn
Posts: 22933
Joined: July 16th, 2004, 7:38 am

Pure virtual functor

March 6th, 2013, 6:11 am

QuoteOriginally posted by: PolterQuoteWhy not use std::function (or boost::function) . . . instead of pure virtual . . . and inheritance?Continuing, now with C++11:http://isocpp.org/blog/2013/03/the-impo ... upkeIndeed! I have been using that for the last 2 years :-) So, hopefully we can expect a lot more discussion now!QuoteThe amazing thing is that calling a std::function is fairly cheap: It?s one virtual function call. That has wide implications for how you will use (or not use) virtual functions in the future. In many cases where you used to have to use a virtual function it is now better to use a std::function. It also means that all the OOP patterns can be replaced by std::function, and not just Observer (which btw can be done automagic with Boost Signals(2)). Nice work by Sutter in 2003 on Observer, 10 years ago!And of course, use std::function and std::bind to bind to OOP ad C legacy code (reusability).// I have examples in the qfcl FD2 and MC1.
Last edited by Cuchulainn on March 5th, 2013, 11:00 pm, edited 1 time in total.