views:

187

answers:

5

Which approach is the better one and why?

template<typename T>
struct assistant {
    T sum(const T& x, const T& y) const { ... }
};

template<typename T>
T operator+ (const T& x, const T& y) {
    assistant<T> t;
    return t.sum(x, y); 
}

Or

template<typename T>
struct assistant {
    static T sum(const T& x, const T& y) { ... }
};

template<typename T>
T operator+ (const T& x, const T& y) {
    return assistant<T>::sum(x, y); 
}

To explain the things a bit more: assistant has no state it only provides several utility functions and later I can define template specialization of it to achieve a different behavior for certain types T.

I think for higher optimization levels these two approaches don't lead to different byte codes because anyway the assistant will optimized "away"...

Thanks!

A: 

In the first method an assistant has to be created while the second method consists of just the function call, thus the second method is faster.

jestro
Not necessarily: gcc with -O3 produces the same byte code for a similar example. I don't know whether I should rely on this in the general case or not.
phlipsy
Both versions will likely generate the same sequence of instructions. Compilers are quite smart these days.
avakar
+3  A: 

Since assistant is essentially a collection of free functions, I would go with the static approach (maybe even make the constructor private). This makes clear that assistant is not intended to be instatiated. Also, and this is only a wild guess, this may result in slightly less memory consumption, since no implicit this-pointer (and no instance of the class) is needed.

Space_C0wb0y
A: 

I'd use the object approach - it seems a bit more standard and similar to the way you pass functors to STL algorithms - it's also easier to extend by allowing parameters passed to the constructor of the assistant to influence the results of the operations etc. There's no difference but the object approach will probably be more flexible long term and more in sync with similar solutions you'll find elsewhere.


Why an object is more flexible? One example is that you can easily implement more complex operations (like average in this example) that require you to store the temporary result "somewhere" and require analyzing results from a couple invocations while still keeping the same "paradigm" of usage. Second might be you'd want to do some optimization - say you need a temporary array to do something in those functions - why allocate it each time or have it static in your class and leave hanging and waste memory when you can allocate it when it's really needed, re-use on a number of elements but then release when all operations are done and the destructor of the object is called.

There's no advantage to using static functions - and as seen above there are at least a few advantages to using objects so the choice is rather simple imho.

Also the calling semantics can be practically identical - Assistant().sum( A, B ) instead of Assistant::sum( A, B ) - there's really little reason to NOT use an object approach :)

RnR
Why do you think is the object approach more flexible in the long term? I can't pass an additional parameter to operator+ with a certain assistant object like they do it in the STL algorithms.
phlipsy
Could you please clarify your edit? Perhaps give a concrete example of the `average` function that would benefit from the "object approach"?
avakar
That's true, *if* (but only if!) I could pass the object to my function. Unfortunately an operator+ doesn't accept further arguments then the two operands x and y.
phlipsy
@philpsy - you said you're building a bigger utility class - I assumed you're going to do a bit more then add elements in it and so the more generic/general approaches might come in handy then.
RnR
@avakar - one example might be:Assistant assistant;assistant.include( a );assistant.include( b );cout << assistant.Average() << assistant.Median() << assistant.Min() << assistant.Max() << assistant.Sum() << assistant.Count() << etc...;Of course you may not need it now - that's why I said it's better long term so when you do start to need something like this the possibility will just be there waiting and nor require you to rewrite everything - if you compare this with a static function giving absolutely zero benefits or advantages long and short term why would you NOT want an object?
RnR
@RnR: In this case the assistant only helps me with certain algebraic operations. Thus in general I can't pass any object instances. To provide both ways for the respective situations seemed too heavy for my situation. BTW: +1 for the reuse argument. Although I can't benefit from it, as yet I didn't considered this point.
phlipsy
@philpsy: Thanks ;) - as to passing objects - you can pass numbers this way too and store them in an array if you need to in the future (a and b are not necessarily "objects" )- some operations will require you to have more and often variable number of arguments and with an object you'll have a choice if you want a ... function, 20 static functions or a single include function that you can call from a loop to gather the arguments :) - using a functor approach will allow you to anything you want in the future so I'd recommend going with it as even the calling code shows no difference at all ;)
RnR
+4  A: 

It is usually not a question of run-time performance, but one of readability. The former version communicates to a potential maintainer that some form of object initialization is performed. The latter makes the intent much clearer and should be (in my opinion) preferred.

By the way, what you've created is basically a traits class. Take a look at how traits are done in the standard library (they use static member functions).

avakar
Readability is in the eye of the beholder. RnR for example likes the second approach more because it's more similar to the STL way passing a functor to an algorithm...
phlipsy
One up for pointing to traits. It's always preferable to refer to some standard solution, since users are more likely to recognize it.
Space_C0wb0y
@philipsy: RnR favours the first approach.
jon hanson
@jon: Of course you're right - a typo!
phlipsy
@avakar: I thought traits only encode characteristics of different types in order to specialize the behaviour of your program at compile time. In my case assistant really does something.
phlipsy
A: 

2nd method is preferred, in this method, there is no strcutre "assistent" variable created and it is calling only required member function. I think it is little bit faster in execution than 1st method.

Red