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