nils
nils

Reputation: 628

Determine type of argument

Is it somehow possible to reflect the type of the argument of a function at compile time?

So that

int b = add(3, 6)

Would result in a template instantiation in the form of

int add(int a, int b) { return a + b }

out of some however declared function template

A add(A a, B b) { return a + b }

I don't know if that is possible with templates they do not really seem to be made for heavy meta-programming.

Upvotes: 0

Views: 834

Answers (5)

Keith
Keith

Reputation: 6834

If you plan on using anything other than simple types you want (in a header file):

template <typename A>
inline A add(const A& a, const A& b) { return a + b; }

Note the 'inline'.

As noted by others, the issue with mixed types is how to determine the return type from the argument types. Suppose we stick to simple types and have:

template inline A add(A a, B b) { return a + b; }

Then this fails (likely with only a warning):

double d = add(1, 1.5); // Sets d to 2.0

So you have to do some work. For example:

template<class A, class B>
struct Promote
{
};

template<class A>
struct Promote<A,A>
{
    typedef  A Type;
};

template<>
struct Promote<int, double>
{
    typedef double Type;
};

template<>
struct Promote<double, int>
{
    typedef double Type;
};

The add function becomes:

template<class A, class B>
inline typename Promote<A,B>::Type add(A a, B b)
{
    return a + b;
}

What all this does for you is ensure that the return type is the one you specify for adding a given pair of types. This will work even for complex types.

Upvotes: 1

Fred Larson
Fred Larson

Reputation: 62053

Doesn't this do what you're asking?

template <typename A, typename B>
A add(A a, B b) { return a + b; }

This is hardly "heavy meta-programming".

Upvotes: 3

Tim
Tim

Reputation: 9172

template<typename T>
T add(T a, T b) { return a + b; }

Then you can call this with any built-in type (int, short, double, float, etc), and it will instantiate the function add at compile time, according to the type you use.

Note that if you split this into header/source, you will have trouble:

add.h:

template<typename T>
T add(T a, T b);

add.cpp:

template<typename T>
T add(T a, T b) { return a + b; }

main.cpp:

#include "add.h"

int a = 3;
int b = 5;
int i = add(a, b);

When you try to compile this, it will fail at link time. Here's why.

Compiling add.obj does not instantiate the add template method -- because it's never called in add.cpp. Compiling main.obj instantiates the function declaration -- but not the function body. So at link time, it will fail to find the definition of the add method.

Simplest fix is to just put the entire template function in the header:

add.h:

template<typename T>
T add(T a, T b) { return a + b; }

and then you don't even need the add.cpp file at all.

Upvotes: 3

aschepler
aschepler

Reputation: 72271

This is exactly the sort of thing templates do.

template <typename T>
inline T add(T a, T b) { return a + b; }

Allowing two different types gets a little bit trickier but is also possible.

Upvotes: 1

Jerry Coffin
Jerry Coffin

Reputation: 490048

Templates do all their magic at compile time, but that seems to be quite adequate for what you're asking:

template <class T>
T add(T a, T b) {  return a + b; }

It does get a bit more complex when the two might not match, so (for example) you could add an int to a double and get a double result. The current standard doesn't really support that1; with C++0x you can look into auto and decltype for such tasks.

1Though Boost typeof will often do the job.

Upvotes: 0

Related Questions