Public Group

# (macros + functions) && (templates) [C++]

This topic is 4705 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Ok, I have two questions. The first: I know about templated classes:
template<class T> class foo { T member; };

But is it possible to just have a templated function? Like this:
template<class T> T add(T x, T y) {return x + y;}

The second question: Whats the difference between a normal function and a macro?
//The macro:
#define ADD(x, y) ((x) + (y))

//The function:
int Add(int x, int y) {return x + y;}


My guess would be that the macro can work with any type, but wouldnt a template fix that? That is, if the answer to my first question is 'yes'.

##### Share on other sites
Yes a function can be templated... I'm just learning about them myself and found a ton of good tutorials on google. Here is one on functions specifically.

##### Share on other sites
Yes, you can have a templated member function, and the syntax looks pretty much like you have. A macro is different from a function in that it does preprocessor text replacement rather compiling a function. If you have your add macro and the following code:
c = Add(a, b);

It changes the code to:
c = a + b;

Before the compiler ever sees the code. To the compiler Add() doesn't exist at all.

##### Share on other sites
Quote:
 Original post by dudedbz1is it possible to just have a templated function? Like this:template T add(T x, T y) {return x + y;}

Certainly.

Quote:
 The second question:Whats the difference between a normal function and a macro?*** Source Snippet Removed ***My guess would be that the macro can work with any type, but wouldnt a template fix that? That is, if the answer to my first question is 'yes'.

A template could be written to emulate that functionality. MACROs can be tricky to use and setup in certain situations, as can templates, but templates have a number of advantages: type safety, scope obedience, flexibility, etc. ... I try and stay away from MACROs myself.

A great book for learning about templates is C++ Templates: A Complete Guide. Highly recommend it.

##### Share on other sites
Quote:
 Original post by dudedbz1Ok, I have two questions. The first:I know about templated classes:template class foo { T member; };But is it possible to just have a templated function? Like this:template T add(T x, T y) {return x + y;}The second question:Whats the difference between a normal function and a macro?*** Source Snippet Removed ***My guess would be that the macro can work with any type, but wouldnt a template fix that? That is, if the answer to my first question is 'yes'.

macros can be a pain because their arguments dont always woek as you intend.

the classic example is

#define SQUARE(X) ( (X) * (X) )

what if you do this:

int other = SQUARE(i++);

it gets inlined into code as

int other = ( (i++) * (i++) );

which increments i twice, but is not immediatly obvious.

templated functions dont have such hidden problems.

the other main difference is that such a templated function is translated at compile time. so it obeys the other rules of the language( it can be part of a namespace etc... ). in c++ the preferred way to have "macro-like" functionality is to used templated functions.

##### Share on other sites
There is some differences between them, lets consider these add functions:

#define Add1(x,y) (x+y)int Add2(int x,int y){    return x+y;}inline int Add3(int x,int y){    return x+y;}template<typename T>T Add4(T x,T y){    return x+y;}template<typename T>inline T Add5(T x,T y){    return x+y;}template<typename T,typename T2>T Add6(T x,T2 y){    return x+y;}template<typename T,typename T2>inline T Add7(T x,T2 y){    return x+y;}template<typename T,typename T2>T Add8(T x,T2 y){    return x+static_cast<T>(y);}template<typename T,typename T2>inline T Add9(T x,T2 y){    return x+static_cast<T>(y);}

Ok we have 9 Add functions, they all add 2 types. The first is the most simple, just a preprocessor function, the preprocessor should be seperate from the C++ compiler so first the preprocessor runs the code and generates code. So imagine this code:
void Foo(){    Add1(5,3);}

The preprocessor will start by generating this code:
void Foo(){    5 + 3 ;}

The problem with this is that it is not typesafe.

The second and third add function is a standard function taking an int. So this restricts the program to only pass integers or at least requires them to convert to integer, so if you have a short (and sizeof(short)!=sizeof(int) which it normally is) then the short will just gets converted without telling you and this could give performance problems if done a lot, from short to integer ain't very bad though. The difference between the second and third is that the third is "inline" which means the compiler tries to put the code "in the line it was called from", so it will try to generate the same code as the preprocessor function. The second is not inlined which means that the program needs to jump to the function and get back again which probably takes much longer than the actual addition, so this is not how you should do it. Note that inline is just a suggestion so the compiler can choose for itself, but any decent compiler should inline both the second and third add function since it is so small.

The fourth and fifth is the same as the second and third, just templated so it can take more types and if you pass another type like a short you don't need to convert it to an integer since it will just perform a short addition.

The sixth and seventh is a little tricky, they take too different (they can also be equal) types which means you can pass a float and a double for example and you don't need to convert one to the other (unless the addition requires it). It only works if we have an addition operator taking T and T2 or we have an implicit conversion from T2 to T.

The eighth and nineth is just like the sixth and seventh they just tries to convert from T2 to T explicitely, so it will probably work with more types, but can be a bit slower since if the types aren't equal we will do the conversion even though an addition operator can take T and T2 we will also convert even though there might be a loss of data, or precision.

We could also have created add functions returning T2 instead of T, but that would just be too complicated. We could also make a T3 which were the return type.

##### Share on other sites
Macros is known to have nasty side effects (for beginners anyway),
aswell as making debugging harder.

If you are using anything "bigger" that a primitive datatype
as the T argument, you should also pass the arguments by referance for better efficiency/speed
template<class T> T add(const T& x, const T& y) {return x + y;}

##### Share on other sites
Quote:
 Original post by pulpfistMacros is known to have nasty side effects (for beginners anyway),aswell as making debugging harder.If you are using anything "bigger" that a primitive datatypeas the T argument, you should also pass the arguments by referance for better efficiency/speedtemplate T add(const T& x, const T& y) {return x + y;}

I have created a little class to solve this problem, I'm still a beginner with template metaprogramming and this is the first thing I try to do so it might not be very good, but I have created a structure with can give you type "const T&" if sizeof(T)>sizeof(T&) and type "const T" if sizeof(T)<=sizeof(T&).

The code for the class is:
/*//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// DOESN'T WORK, SEE POLYMORPHIC OOP'S POST// I will leave it here though so people can see// what he is talking about, but don't use it.//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////template<typename T>struct ReadOnlyValue{	// Get the size of a reference to T and the type itself so we can later compare and	// choose what to use.	enum	{		ReferenceSize = sizeof(const T&),		ValueSize = sizeof(const T)	};	template<bool UseValueType>	struct _Type;	template<>		struct _Type<true>	{		typedef const T Type;	};	template<>		struct _Type<false>	{		typedef const T& Type;	};	typedef typename _Type<ReferenceSize>=ValueSize>::Type Type;};*/

EDIT: But this stuff is in most cases not worth doing.

[Edited by - CTar on November 5, 2005 3:58:23 PM]

##### Share on other sites
I would like to point out that macros don't inherently have the problems mentioned. C and C++ macros do, but (for example) Scheme's hygienic macros don't.

##### Share on other sites
Quote:
 Original post by RoboguyI would like to point out that macros don't inherently have the problems mentioned. C and C++ macros do, but (for example) Scheme's hygienic macros don't.

Of course, the OP isn't refering to Scheme. So your comment is completely pointless.

CM

1. 1
2. 2
3. 3
Rutin
18
4. 4
JoeJ
14
5. 5

• 14
• 10
• 23
• 9
• 32
• ### Forum Statistics

• Total Topics
632630
• Total Posts
3007521
• ### Who's Online (See full list)

There are no registered users currently online

×