By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
457,915 Members | 1,339 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 457,915 IT Pros & Developers. It's quick & easy.

macro vs. template???

P: n/a
Hi everyone. A very simple question. I would like to know what is
better in terms of performance. I want to use a simple function to
obtain the minimum of two values. One way could be using a macro:

#define min(a,b) ((a<b)?a:b)

I thought that another way could be to use a template function:

template <class T>
T min<T a, T b>
{
if(a < b)
return a;
else
return b;
}

Any ideas on which way is better to implement? I guess that whenever I
use the template function is going to help me check at compile time.
Also, for some reason I don't like using macros. Thank you.

Oct 25 '06 #1
Share this Question
Share on Google+
19 Replies


P: n/a
aaragon wrote:
Hi everyone. A very simple question. I would like to know what is
better in terms of performance. I want to use a simple function to
obtain the minimum of two values. One way could be using a macro:

#define min(a,b) ((a<b)?a:b)

I thought that another way could be to use a template function:

template <class T>
T min<T a, T b>
{
if(a < b)
return a;
else
return b;
}

Any ideas on which way is better to implement? I guess that whenever I
use the template function is going to help me check at compile time.
Also, for some reason I don't like using macros. Thank you.
What did you profiler show you?

Follow your instinct and don't use macros.

--
Ian Collins.
Oct 25 '06 #2

P: n/a

aaragon wrote:
Hi everyone. A very simple question. I would like to know what is
better in terms of performance. I want to use a simple function to
obtain the minimum of two values. One way could be using a macro:

#define min(a,b) ((a<b)?a:b)

I thought that another way could be to use a template function:

template <class T>
T min<T a, T b>
{
if(a < b)
return a;
else
return b;
}
Version two has better type safety. Not much can go wrong with that
little function but regardless, practice is better in the second. You
might consider references though.
Any ideas on which way is better to implement? I guess that whenever I
use the template function is going to help me check at compile time.
Also, for some reason I don't like using macros. Thank you.
There is no reason to not like using macros. Use them when
appropriate. Macros just aren't appropriate for inline stuff in
C++...you should use inline functions (don't have to be templates).

Oct 25 '06 #3

P: n/a
aaragon wrote:
Hi everyone. A very simple question. I would like to know what is
better in terms of performance. I want to use a simple function to
obtain the minimum of two values. One way could be using a macro:

#define min(a,b) ((a<b)?a:b)

I thought that another way could be to use a template function:

template <class T>
T min<T a, T b>
{
if(a < b)
return a;
else
return b;
}

Any ideas on which way is better to implement? I guess that whenever I
use the template function is going to help me check at compile time.
Also, for some reason I don't like using macros. Thank you.
Why not use std::min() from <algorithm?
Best

Kai-Uwe Bux
Oct 25 '06 #4

P: n/a
Noah Roberts wrote:
There is no reason to not like using macros. Use them when
appropriate. Macros just aren't appropriate for inline stuff in
C++...you should use inline functions (don't have to be templates).
Further, inline doesn't automatically mean faster.

In general, programmers rarely need to worry about performance at the level
of individual statements and functions. Write your code, make it clean, and
upgrade its algorithm, and you should be fine.

Lots of C++ tutorials talk about optimization as if that's what we do all
day. Optimization comes down to the 'if' statements only very rarely.
Premature optimization is the root of all evil; you should think of clear
and expressive statements, first. (That means min should be a template
function, because that's easiest to get right without worrying about it.)

--
Phlip
http://www.greencheese.us/ZeekLand <-- NOT a blog!!!
Oct 25 '06 #5

P: n/a
aaragon wrote:
Hi everyone. A very simple question. I would like to know what is
better in terms of performance. I want to use a simple function to
obtain the minimum of two values. One way could be using a macro:

#define min(a,b) ((a<b)?a:b)

I thought that another way could be to use a template function:

template <class T>
T min<T a, T b>
{
if(a < b)
return a;
else
return b;
}

Any ideas on which way is better to implement? I guess that whenever I
use the template function is going to help me check at compile time.
Also, for some reason I don't like using macros. Thank you.
Unlikely you'll notice a performance difference but note that you've
chosen a notoriously bad macro as your example. If expression a or b
has any side effects then these two are not equivalent. Additionally,
that you haven't enclosed all occurrences of a and b in parentheses in
the macro definition leaves open the possibility of subtle errors due to
operator precedence.
Oct 25 '06 #6

P: n/a

Mark P wrote:
aaragon wrote:
Hi everyone. A very simple question. I would like to know what is
better in terms of performance. I want to use a simple function to
obtain the minimum of two values. One way could be using a macro:

#define min(a,b) ((a<b)?a:b)

I thought that another way could be to use a template function:

template <class T>
T min<T a, T b>
{
if(a < b)
return a;
else
return b;
}

Any ideas on which way is better to implement? I guess that whenever I
use the template function is going to help me check at compile time.
Also, for some reason I don't like using macros. Thank you.

Unlikely you'll notice a performance difference but note that you've
chosen a notoriously bad macro as your example. If expression a or b
has any side effects then these two are not equivalent. Additionally,
that you haven't enclosed all occurrences of a and b in parentheses in
the macro definition leaves open the possibility of subtle errors due to
operator precedence.
Thanks everybody for your answers. I will stick to the template for
safety reasons. I never worked with inline functions so I don't know
what benefits they have.

Oct 26 '06 #7

P: n/a
aaragon wrote:
>
Thanks everybody for your answers. I will stick to the template for
safety reasons. I never worked with inline functions so I don't know
what benefits they have.
Have you ever written trivial method bodies in a class declaration? If
so, you have worked with inline functions.

You compiler will inline small methods when you compile with
optimisation, so don't get too hung up on what is and what isn't an
inline function.

--
Ian Collins.
Oct 26 '06 #8

P: n/a

aaragon wrote:
Hi everyone. A very simple question. I would like to know what is
better in terms of performance. I want to use a simple function to
obtain the minimum of two values. One way could be using a macro:

#define min(a,b) ((a<b)?a:b)

I thought that another way could be to use a template function:

template <class T>
T min<T a, T b>
{
if(a < b)
return a;
else
return b;
}

Any ideas on which way is better to implement? I guess that whenever I
use the template function is going to help me check at compile time.
Also, for some reason I don't like using macros. Thank you.
There is a lot more depth to this question than what most people would
ever really imagine. See the following article by Andrei Alexandrescu:

http://www.ddj.com/dept/cpp/184403774

--
Alan Johnson

Oct 26 '06 #9

P: n/a

Alan Johnson wrote:
aaragon wrote:
Hi everyone. A very simple question. I would like to know what is
better in terms of performance. I want to use a simple function to
obtain the minimum of two values. One way could be using a macro:

#define min(a,b) ((a<b)?a:b)

I thought that another way could be to use a template function:

template <class T>
T min<T a, T b>
{
if(a < b)
return a;
else
return b;
}

Any ideas on which way is better to implement? I guess that whenever I
use the template function is going to help me check at compile time.
Also, for some reason I don't like using macros. Thank you.

There is a lot more depth to this question than what most people would
ever really imagine. See the following article by Andrei Alexandrescu:

http://www.ddj.com/dept/cpp/184403774

--
Alan Johnson
I never thought that a min function using templates was so complicated.
Untl I understand what Alexandrescu is doing, I finally decided to
stick to the macro version.

Thanks Alan for pointing out that article.

Oct 26 '06 #10

P: n/a

Ian Collins wrote:
aaragon wrote:

Thanks everybody for your answers. I will stick to the template for
safety reasons. I never worked with inline functions so I don't know
what benefits they have.
Have you ever written trivial method bodies in a class declaration? If
so, you have worked with inline functions.

You compiler will inline small methods when you compile with
optimisation, so don't get too hung up on what is and what isn't an
inline function.

--
Ian Collins.
Ian, I see what you mean with that. Do I put the "inline" word in
front of the trivial method so that it can be inlined by the compiler?
Or the compiler knows that the method can be inlined by its own?

Oct 26 '06 #11

P: n/a
aaragon wrote:
Ian Collins wrote:
>>aaragon wrote:
>>>Thanks everybody for your answers. I will stick to the template for
safety reasons. I never worked with inline functions so I don't know
what benefits they have.

Have you ever written trivial method bodies in a class declaration? If
so, you have worked with inline functions.

You compiler will inline small methods when you compile with
optimisation, so don't get too hung up on what is and what isn't an
inline function.

--
Ian Collins.


Ian, I see what you mean with that. Do I put the "inline" word in
front of the trivial method so that it can be inlined by the compiler?
Or the compiler knows that the method can be inlined by its own?
'inline' is nothing more than a hint.

Modern compilers (especially if they have profiling feedback) do a
decent job on their own. That's one of the beauties of C++, you can
write short functions with descriptive names to improve the readability
of your code knowing the compiler will inline them.

--
Ian Collins.
Oct 26 '06 #12

P: n/a
aaragon wrote:
Alan Johnson wrote:
>>aaragon wrote:
>>>Hi everyone. A very simple question. I would like to know what is
better in terms of performance. I want to use a simple function to
obtain the minimum of two values. One way could be using a macro:

#define min(a,b) ((a<b)?a:b)

I thought that another way could be to use a template function:

template <class T>
T min<T a, T b>
{
if(a < b)
return a;
else
return b;
}

Any ideas on which way is better to implement? I guess that whenever I
use the template function is going to help me check at compile time.
Also, for some reason I don't like using macros. Thank you.

There is a lot more depth to this question than what most people would
ever really imagine. See the following article by Andrei Alexandrescu:

http://www.ddj.com/dept/cpp/184403774

I never thought that a min function using templates was so complicated.
Untl I understand what Alexandrescu is doing, I finally decided to
stick to the macro version.
Better to do as Kai-Uwe Bux suggested and use std::min().

--
Ian Collins.
Oct 26 '06 #13

P: n/a

"aaragon" <al**************@gmail.comwrote in message
news:11**********************@m73g2000cwd.googlegr oups.com...
I never thought that a min function using templates was so complicated.
Untl I understand what Alexandrescu is doing, I finally decided to
stick to the macro version.

Thanks Alan for pointing out that article.
Don't fret, the article overshoots in one crucial way: Who will
ever need a min() or max() function that returns either a const
or a non-const reference based on the *run-time* values of
its arguments?

Put differently, the article aims to make something like this to
compileable:

int r = rand();
const int s = rand();
max( r,s ) = rand();

The real question is, why should it compile?!? If there's mixed
constness in the arguments of max() or min(), and the run-time
values of said arguments determine the result, then how can
the programmer expect the assignment to succeed if the result
turns out to be the const one?

(BTW, It's entirely possible that I'm missing some significant
point in my criticism, in which case please educate me.)

- Risto -
Oct 26 '06 #14

P: n/a
aaragon wrote:
Hi everyone. A very simple question. I would like to know what is
better in terms of performance. I want to use a simple function to
obtain the minimum of two values. One way could be using a macro:

#define min(a,b) ((a<b)?a:b)

I thought that another way could be to use a template function:

template <class T>
T min<T a, T b>
{
if(a < b)
return a;
else
return b;
}

Any ideas on which way is better to implement? I guess that whenever I
use the template function is going to help me check at compile time.
Also, for some reason I don't like using macros. Thank you.
Well they aren't semantically equivalent. The first one evaluates
the expression that is the smallest value twice.
Oct 26 '06 #15

P: n/a
VJ
aaragon wrote:
Ian Collins wrote:
>>aaragon wrote:
>>>Thanks everybody for your answers. I will stick to the template for
safety reasons. I never worked with inline functions so I don't know
what benefits they have.

Have you ever written trivial method bodies in a class declaration? If
so, you have worked with inline functions.

You compiler will inline small methods when you compile with
optimisation, so don't get too hung up on what is and what isn't an
inline function.

--
Ian Collins.


Ian, I see what you mean with that. Do I put the "inline" word in
front of the trivial method so that it can be inlined by the compiler?
Or the compiler knows that the method can be inlined by its own?
"Premature optimization is the root of all evil"

Sometimes puting inline can make your program go slower.
Oct 26 '06 #16

P: n/a
aaragon wrote:
Hi everyone. A very simple question. I would like to know what is
better in terms of performance. I want to use a simple function to
obtain the minimum of two values. One way could be using a macro:

#define min(a,b) ((a<b)?a:b)
Wait a minute, you have not yet been bitten by the macro bug.

If you are going to use the macro, you need to change it to:

#define min(a,b) ((a)<(b)?(a):(b))

Precedence of the "<" operator can be higher that other operators and
you could be evaluating something different to what you expect.
>
I thought that another way could be to use a template function:

template <class T>
T min<T a, T b>
{
if(a < b)
return a;
else
return b;
}
The problem with this is you're passing in copies. If it is a non
trivial type you could be incurring an overhead.

template <class T>
const T & min<const T & a, const T & b>
{
if(a < b)
return a;
else
return b;
}

The problem with this is that it won't work for different types, e.g.

min(1,0.2) will fail to find a match with the min() above.

So you can change it to:

template <class T1, class T2>
T1 min<const T1 & a, const T2 & b>
{
if(a < b)
return a;
else
return b;
}

OK - now you have a problem with promotion of the return value.

min(1,0.1) returns 0, not 0.1.

What type should the return type be ? See the lengthy "Promote" class
below that will help you work it out.

template <class T1, class T2>
typename Promote<T1,T2>::type min<const T1 & a, const T2 & b>
{
if(a < b)
return a;
else
return b;
}

This will do what you expect it to do. As for efficiency, the compiler
can quite easily optimize this, inline it or whatever.
>
Any ideas on which way is better to implement? I guess that whenever I
use the template function is going to help me check at compile time.
The biggest problem with using using macros is when you do things like:

int x = min(++y,x--);

If you use a macro, you're sol because you have a problem.
Also, for some reason I don't like using macros. Thank you.

I think I have posted this one before. If c++ had a "typeof", we could
do away with this nonsense.
// ======== Promote ===============================================
/**
* This template allows you to determine the type that the compiler
* will promote an arithmetic expression to.
*/
template <typename T1, typename T2>
struct Promote
{
};

// the same types are the same ! cool
// this should also make POD types work

template <typename T1>
struct Promote<T1,T1>
{
typedef T1 type;
};

// specify all the type promotions ...

template <struct Promote<unsigned char,char{ typedef int type; };
template <struct Promote<signed char,char{ typedef int type; };
template <struct Promote<short,char{ typedef int type; };
template <struct Promote<unsigned short,char{ typedef int type; };
template <struct Promote<int,char{ typedef int type; };
template <struct Promote<unsigned int,char{ typedef unsigned int
type; };
template <struct Promote<long,char{ typedef long type; };
template <struct Promote<unsigned long,char{ typedef unsigned long
type; };
template <struct Promote<long long,char{ typedef long long type; };
template <struct Promote<unsigned long long,char{ typedef unsigned
long long type; };
template <struct Promote<float,char{ typedef float type; };
template <struct Promote<double,char{ typedef double type; };
template <struct Promote<long double,char{ typedef long double type; };
template <struct Promote<char,unsigned char{ typedef int type; };
template <struct Promote<signed char,unsigned char{ typedef int type; };
template <struct Promote<short,unsigned char{ typedef int type; };
template <struct Promote<unsigned short,unsigned char{ typedef int
type; };
template <struct Promote<int,unsigned char{ typedef int type; };
template <struct Promote<unsigned int,unsigned char{ typedef
unsigned int type; };
template <struct Promote<long,unsigned char{ typedef long type; };
template <struct Promote<unsigned long,unsigned char{ typedef
unsigned long type; };
template <struct Promote<long long,unsigned char{ typedef long long
type; };
template <struct Promote<unsigned long long,unsigned char{ typedef
unsigned long long type; };
template <struct Promote<float,unsigned char{ typedef float type; };
template <struct Promote<double,unsigned char{ typedef double type; };
template <struct Promote<long double,unsigned char{ typedef long
double type; };
template <struct Promote<char,signed char{ typedef int type; };
template <struct Promote<unsigned char,signed char{ typedef int type; };
template <struct Promote<short,signed char{ typedef int type; };
template <struct Promote<unsigned short,signed char{ typedef int
type; };
template <struct Promote<int,signed char{ typedef int type; };
template <struct Promote<unsigned int,signed char{ typedef unsigned
int type; };
template <struct Promote<long,signed char{ typedef long type; };
template <struct Promote<unsigned long,signed char{ typedef unsigned
long type; };
template <struct Promote<long long,signed char{ typedef long long
type; };
template <struct Promote<unsigned long long,signed char{ typedef
unsigned long long type; };
template <struct Promote<float,signed char{ typedef float type; };
template <struct Promote<double,signed char{ typedef double type; };
template <struct Promote<long double,signed char{ typedef long
double type; };
template <struct Promote<char,short{ typedef int type; };
template <struct Promote<unsigned char,short{ typedef int type; };
template <struct Promote<signed char,short{ typedef int type; };
template <struct Promote<unsigned short,short{ typedef int type; };
template <struct Promote<int,short{ typedef int type; };
template <struct Promote<unsigned int,short{ typedef unsigned int
type; };
template <struct Promote<long,short{ typedef long type; };
template <struct Promote<unsigned long,short{ typedef unsigned long
type; };
template <struct Promote<long long,short{ typedef long long type; };
template <struct Promote<unsigned long long,short{ typedef unsigned
long long type; };
template <struct Promote<float,short{ typedef float type; };
template <struct Promote<double,short{ typedef double type; };
template <struct Promote<long double,short{ typedef long double type; };
template <struct Promote<char,unsigned short{ typedef int type; };
template <struct Promote<unsigned char,unsigned short{ typedef int
type; };
template <struct Promote<signed char,unsigned short{ typedef int
type; };
template <struct Promote<short,unsigned short{ typedef int type; };
template <struct Promote<int,unsigned short{ typedef int type; };
template <struct Promote<unsigned int,unsigned short{ typedef
unsigned int type; };
template <struct Promote<long,unsigned short{ typedef long type; };
template <struct Promote<unsigned long,unsigned short{ typedef
unsigned long type; };
template <struct Promote<long long,unsigned short{ typedef long long
type; };
template <struct Promote<unsigned long long,unsigned short{ typedef
unsigned long long type; };
template <struct Promote<float,unsigned short{ typedef float type; };
template <struct Promote<double,unsigned short{ typedef double type; };
template <struct Promote<long double,unsigned short{ typedef long
double type; };
template <struct Promote<char,int{ typedef int type; };
template <struct Promote<unsigned char,int{ typedef int type; };
template <struct Promote<signed char,int{ typedef int type; };
template <struct Promote<short,int{ typedef int type; };
template <struct Promote<unsigned short,int{ typedef int type; };
template <struct Promote<unsigned int,int{ typedef unsigned int type; };
template <struct Promote<long,int{ typedef long type; };
template <struct Promote<unsigned long,int{ typedef unsigned long
type; };
template <struct Promote<long long,int{ typedef long long type; };
template <struct Promote<unsigned long long,int{ typedef unsigned
long long type; };
template <struct Promote<float,int{ typedef float type; };
template <struct Promote<double,int{ typedef double type; };
template <struct Promote<long double,int{ typedef long double type; };
template <struct Promote<char,unsigned int{ typedef unsigned int
type; };
template <struct Promote<unsigned char,unsigned int{ typedef
unsigned int type; };
template <struct Promote<signed char,unsigned int{ typedef unsigned
int type; };
template <struct Promote<short,unsigned int{ typedef unsigned int
type; };
template <struct Promote<unsigned short,unsigned int{ typedef
unsigned int type; };
template <struct Promote<int,unsigned int{ typedef unsigned int type; };
template <struct Promote<long,unsigned int{ typedef unsigned long
type; };
template <struct Promote<unsigned long,unsigned int{ typedef
unsigned long type; };
template <struct Promote<long long,unsigned int{ typedef long long
type; };
template <struct Promote<unsigned long long,unsigned int{ typedef
unsigned long long type; };
template <struct Promote<float,unsigned int{ typedef float type; };
template <struct Promote<double,unsigned int{ typedef double type; };
template <struct Promote<long double,unsigned int{ typedef long
double type; };
template <struct Promote<char,long{ typedef long type; };
template <struct Promote<unsigned char,long{ typedef long type; };
template <struct Promote<signed char,long{ typedef long type; };
template <struct Promote<short,long{ typedef long type; };
template <struct Promote<unsigned short,long{ typedef long type; };
template <struct Promote<int,long{ typedef long type; };
template <struct Promote<unsigned int,long{ typedef unsigned long
type; };
template <struct Promote<unsigned long,long{ typedef unsigned long
type; };
template <struct Promote<long long,long{ typedef long long type; };
template <struct Promote<unsigned long long,long{ typedef unsigned
long long type; };
template <struct Promote<float,long{ typedef float type; };
template <struct Promote<double,long{ typedef double type; };
template <struct Promote<long double,long{ typedef long double type; };
template <struct Promote<char,unsigned long{ typedef unsigned long
type; };
template <struct Promote<unsigned char,unsigned long{ typedef
unsigned long type; };
template <struct Promote<signed char,unsigned long{ typedef unsigned
long type; };
template <struct Promote<short,unsigned long{ typedef unsigned long
type; };
template <struct Promote<unsigned short,unsigned long{ typedef
unsigned long type; };
template <struct Promote<int,unsigned long{ typedef unsigned long
type; };
template <struct Promote<unsigned int,unsigned long{ typedef
unsigned long type; };
template <struct Promote<long,unsigned long{ typedef unsigned long
type; };
template <struct Promote<long long,unsigned long{ typedef long long
type; };
template <struct Promote<unsigned long long,unsigned long{ typedef
unsigned long long type; };
template <struct Promote<float,unsigned long{ typedef float type; };
template <struct Promote<double,unsigned long{ typedef double type; };
template <struct Promote<long double,unsigned long{ typedef long
double type; };
template <struct Promote<char,long long{ typedef long long type; };
template <struct Promote<unsigned char,long long{ typedef long long
type; };
template <struct Promote<signed char,long long{ typedef long long
type; };
template <struct Promote<short,long long{ typedef long long type; };
template <struct Promote<unsigned short,long long{ typedef long long
type; };
template <struct Promote<int,long long{ typedef long long type; };
template <struct Promote<unsigned int,long long{ typedef long long
type; };
template <struct Promote<long,long long{ typedef long long type; };
template <struct Promote<unsigned long,long long{ typedef long long
type; };
template <struct Promote<unsigned long long,long long{ typedef
unsigned long long type; };
template <struct Promote<float,long long{ typedef float type; };
template <struct Promote<double,long long{ typedef double type; };
template <struct Promote<long double,long long{ typedef long double
type; };
template <struct Promote<char,unsigned long long{ typedef unsigned
long long type; };
template <struct Promote<unsigned char,unsigned long long{ typedef
unsigned long long type; };
template <struct Promote<signed char,unsigned long long{ typedef
unsigned long long type; };
template <struct Promote<short,unsigned long long{ typedef unsigned
long long type; };
template <struct Promote<unsigned short,unsigned long long{ typedef
unsigned long long type; };
template <struct Promote<int,unsigned long long{ typedef unsigned
long long type; };
template <struct Promote<unsigned int,unsigned long long{ typedef
unsigned long long type; };
template <struct Promote<long,unsigned long long{ typedef unsigned
long long type; };
template <struct Promote<unsigned long,unsigned long long{ typedef
unsigned long long type; };
template <struct Promote<long long,unsigned long long{ typedef
unsigned long long type; };
template <struct Promote<float,unsigned long long{ typedef float
type; };
template <struct Promote<double,unsigned long long{ typedef double
type; };
template <struct Promote<long double,unsigned long long{ typedef
long double type; };
template <struct Promote<char,float{ typedef float type; };
template <struct Promote<unsigned char,float{ typedef float type; };
template <struct Promote<signed char,float{ typedef float type; };
template <struct Promote<short,float{ typedef float type; };
template <struct Promote<unsigned short,float{ typedef float type; };
template <struct Promote<int,float{ typedef float type; };
template <struct Promote<unsigned int,float{ typedef float type; };
template <struct Promote<long,float{ typedef float type; };
template <struct Promote<unsigned long,float{ typedef float type; };
template <struct Promote<long long,float{ typedef float type; };
template <struct Promote<unsigned long long,float{ typedef float
type; };
template <struct Promote<double,float{ typedef double type; };
template <struct Promote<long double,float{ typedef long double type; };
template <struct Promote<char,double{ typedef double type; };
template <struct Promote<unsigned char,double{ typedef double type; };
template <struct Promote<signed char,double{ typedef double type; };
template <struct Promote<short,double{ typedef double type; };
template <struct Promote<unsigned short,double{ typedef double type; };
template <struct Promote<int,double{ typedef double type; };
template <struct Promote<unsigned int,double{ typedef double type; };
template <struct Promote<long,double{ typedef double type; };
template <struct Promote<unsigned long,double{ typedef double type; };
template <struct Promote<long long,double{ typedef double type; };
template <struct Promote<unsigned long long,double{ typedef double
type; };
template <struct Promote<float,double{ typedef double type; };
template <struct Promote<long double,double{ typedef long double
type; };
template <struct Promote<char,long double{ typedef long double type; };
template <struct Promote<unsigned char,long double{ typedef long
double type; };
template <struct Promote<signed char,long double{ typedef long
double type; };
template <struct Promote<short,long double{ typedef long double type; };
template <struct Promote<unsigned short,long double{ typedef long
double type; };
template <struct Promote<int,long double{ typedef long double type; };
template <struct Promote<unsigned int,long double{ typedef long
double type; };
template <struct Promote<long,long double{ typedef long double type; };
template <struct Promote<unsigned long,long double{ typedef long
double type; };
template <struct Promote<long long,long double{ typedef long double
type; };
template <struct Promote<unsigned long long,long double{ typedef
long double type; };
template <struct Promote<float,long double{ typedef long double type; };
template <struct Promote<double,long double{ typedef long double
type; };
Oct 26 '06 #17

P: n/a

Gianni Mariani wrote:
[snip]
Wait a minute, you have not yet been bitten by the macro bug.

If you are going to use the macro, you need to change it to:

#define min(a,b) ((a)<(b)?(a):(b))
[snip]
>
template <class T>
const T & min<const T & a, const T & b>
{
if(a < b)
return a;
else
return b;
}

The problem with this is that it won't work for different types, e.g.

min(1,0.2) will fail to find a match with the min() above.
And so what? You'd write min(1.0,0.2), wouldn't you? ;-)
Really - this is a trivial problem that should rarely occur in
practical life. In those few cases where it happens, the error-message
requires you to make a decision and write e.g. min<double>(i,2.71).

This is a good thing, forcing you to think about why you use two
different types in the first place.

/Peter

Oct 26 '06 #18

P: n/a
peter koch wrote:
Gianni Mariani wrote:
[snip]
>Wait a minute, you have not yet been bitten by the macro bug.

If you are going to use the macro, you need to change it to:

#define min(a,b) ((a)<(b)?(a):(b))
[snip]
>template <class T>
const T & min<const T & a, const T & b>
{
if(a < b)
return a;
else
return b;
}

The problem with this is that it won't work for different types, e.g.

min(1,0.2) will fail to find a match with the min() above.

And so what? You'd write min(1.0,0.2), wouldn't you? ;-)
Really - this is a trivial problem that should rarely occur in
practical life. In those few cases where it happens, the error-message
requires you to make a decision and write e.g. min<double>(i,2.71).

This is a good thing, forcing you to think about why you use two
different types in the first place.
I'm probably on your side of the fence.

There are people out there who want the macro like min() functionality
which means type promotion is needed.

Funny enough, I use the type promotion thing in some vector arithmetic
templates where the result type is determined by the types being passed
in. For example, multiplying a vector of floats by a double gets a
vector of double.

Oct 26 '06 #19

P: n/a

Gianni Mariani wrote:
aaragon wrote:
Hi everyone. A very simple question. I would like to know what is
better in terms of performance. I want to use a simple function to
obtain the minimum of two values. One way could be using a macro:

#define min(a,b) ((a<b)?a:b)

Wait a minute, you have not yet been bitten by the macro bug.

If you are going to use the macro, you need to change it to:

#define min(a,b) ((a)<(b)?(a):(b))

Precedence of the "<" operator can be higher that other operators and
you could be evaluating something different to what you expect.

I thought that another way could be to use a template function:

template <class T>
T min<T a, T b>
{
if(a < b)
return a;
else
return b;
}

The problem with this is you're passing in copies. If it is a non
trivial type you could be incurring an overhead.

template <class T>
const T & min<const T & a, const T & b>
{
if(a < b)
return a;
else
return b;
}
Well, I still like the other approach since I'm using primitive types.
For primitive types, it is faster passing by value according to
Alexandrescu's book.
The problem with this is that it won't work for different types, e.g.

min(1,0.2) will fail to find a match with the min() above.

So you can change it to:

template <class T1, class T2>
T1 min<const T1 & a, const T2 & b>
{
if(a < b)
return a;
else
return b;
}
I don't like the idea of comparing apples to oranges to obtain a
minimum. If I use one type, there is going to be a compiler error and
I will know that I'm doing something wrong with my code.

OK - now you have a problem with promotion of the return value.

min(1,0.1) returns 0, not 0.1.

What type should the return type be ? See the lengthy "Promote" class
below that will help you work it out.

template <class T1, class T2>
typename Promote<T1,T2>::type min<const T1 & a, const T2 & b>
{
if(a < b)
return a;
else
return b;
}

This will do what you expect it to do. As for efficiency, the compiler
can quite easily optimize this, inline it or whatever.

Any ideas on which way is better to implement? I guess that whenever I
use the template function is going to help me check at compile time.

The biggest problem with using using macros is when you do things like:

int x = min(++y,x--);

If you use a macro, you're sol because you have a problem.
Also, for some reason I don't like using macros. Thank you.


I think I have posted this one before. If c++ had a "typeof", we could
do away with this nonsense.
Oct 26 '06 #20

This discussion thread is closed

Replies have been disabled for this discussion.