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

problem on function template

P: n/a
Dear All,

Assume I have two templates as follows:

//! Add #1: p3 = p1 + p2.
template<class _T1, class _T2, class _T3>
void Add(const _T1 *p1, const _T2 *p2, _T3 *p3, size_t n)
{
for (size_t i = 0; i < n; ++i) p3[i] = p1[i] + p2[2];
}

//! Add #2: p3 = p1 + d2.
template<class _T1, class _T2, class _T3>
void Add(const _T1 *p1, const _T2 d2, _T3 *p3, size_t n)
{
for (size_t i = 0; i < n; ++i) p3[i] = p1[i] + d2;
}

Where p1, p2, p3 are pointers pointing to a group of data, and d2 is
just a single data.

I test the following case:

//! A test.
int *p1 = new int [3]; p1[0] = 1; p1[0] = 2; p1[0] = 3;
int *p2 = new int [3]; p2[0] = 1; p2[0] = 2; p2[0] = 3;
int *p3 = new int [3];
Add(p1, p2, p3, 3);

And I find that the "Add(p1, p2, p3, 3)" tries to call the second
template and givea a compilor error like can not convert int* to int.
In fact the first template can also allow the calling and it will give
the right results. I can change the seconde template name to "Add2" to
get it right. Is there any better way to accomplish it.

Thanks,

Shuisheng

Sep 28 '06 #1
Share this Question
Share on Google+
5 Replies


P: n/a
shuisheng wrote:
Assume I have two templates as follows:

//! Add #1: p3 = p1 + p2.
template<class _T1, class _T2, class _T3>
It has been already suggested, drop the leading underscores. With
them your code is illegal and difficult to read.
void Add(const _T1 *p1, const _T2 *p2, _T3 *p3, size_t n)
{
for (size_t i = 0; i < n; ++i) p3[i] = p1[i] + p2[2];
}

//! Add #2: p3 = p1 + d2.
template<class _T1, class _T2, class _T3>
void Add(const _T1 *p1, const _T2 d2, _T3 *p3, size_t n)
{
for (size_t i = 0; i < n; ++i) p3[i] = p1[i] + d2;
}

Where p1, p2, p3 are pointers pointing to a group of data, and d2 is
just a single data.

I test the following case:

//! A test.
int *p1 = new int [3]; p1[0] = 1; p1[0] = 2; p1[0] = 3;
int *p2 = new int [3]; p2[0] = 1; p2[0] = 2; p2[0] = 3;
int *p3 = new int [3];
Add(p1, p2, p3, 3);

And I find that the "Add(p1, p2, p3, 3)" tries to call the second
template and givea a compilor error like can not convert int* to int.
Correct. The compiler figures that T2 is "pointer to int" (the top-level
'const' qualifier is dropped), and that matches the type of 'p2' better
than 'const T2*' (with T2 'int') because the latter would require
a qualification conversion.
In fact the first template can also allow the calling and it will give
the right results. I can change the seconde template name to "Add2" to
get it right. Is there any better way to accomplish it.
Why are your 'Tx' types all different? Do they have to be? Couldn't you
simply have a single template argument:

template<class Tvoid Add(const T* p1, const T* p2, T* p3, size_t n)

and

template<class Tvoid Add(const T* p1, T d2, T* p3, size_t n)

? That would resolve the "ambiguity".

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Sep 28 '06 #2

P: n/a

shuisheng wrote:
Dear All,

Assume I have two templates as follows:

//! Add #1: p3 = p1 + p2.
template<class _T1, class _T2, class _T3>
void Add(const _T1 *p1, const _T2 *p2, _T3 *p3, size_t n)
{
for (size_t i = 0; i < n; ++i) p3[i] = p1[i] + p2[2];
}

//! Add #2: p3 = p1 + d2.
template<class _T1, class _T2, class _T3>
void Add(const _T1 *p1, const _T2 d2, _T3 *p3, size_t n)
{
for (size_t i = 0; i < n; ++i) p3[i] = p1[i] + d2;
}

Where p1, p2, p3 are pointers pointing to a group of data, and d2 is
just a single data.

I test the following case:

//! A test.
int *p1 = new int [3]; p1[0] = 1; p1[0] = 2; p1[0] = 3;
int *p2 = new int [3]; p2[0] = 1; p2[0] = 2; p2[0] = 3;
int *p3 = new int [3];
Add(p1, p2, p3, 3);

And I find that the "Add(p1, p2, p3, 3)" tries to call the second
template and givea a compilor error like can not convert int* to int.
In fact the first template can also allow the calling and it will give
the right results. I can change the seconde template name to "Add2" to
get it right. Is there any better way to accomplish it.

Thanks,
That's because the second function is more specialized than the first
function and the partial ordering rules come into the picture.
Basically in the first one T2 is deduced to be an int
and in the second case T2 is deduced to be an int*...

and if you use substitution rules governed by the partial ordering
mechanism, the second one is more specialized.
>
Shuisheng
Sep 28 '06 #3

P: n/a

Victor Bazarov 写道:
Why are your 'Tx' types all different? Do they have to be? Couldn't you
simply have a single template argument:

template<class Tvoid Add(const T* p1, const T* p2, T* p3, size_t n)

and

template<class Tvoid Add(const T* p1, T d2, T* p3, size_t n)

? That would resolve the "ambiguity".
That is because we mix-used the float and double type in our team
project.

Sep 28 '06 #4

P: n/a
shuisheng wrote:
Victor Bazarov ??:
>Why are your 'Tx' types all different? Do they have to be?
Couldn't you simply have a single template argument:

template<class Tvoid Add(const T* p1, const T* p2, T* p3,
size_t n)

and

template<class Tvoid Add(const T* p1, T d2, T* p3, size_t n)

? That would resolve the "ambiguity".

That is because we mix-used the float and double type in our team
project.
Ah.... I see. I was afraid you might say something like that :-)

One solution is to overload your function to make the second 'Add'
take 'double' as the second argument:
~~~~~~~~~~~~~~~~~
template<class T1, class T3void Add(const T1* p1, double d2,
const T3* p3, size_t n);
~~~~~~~~~~~~~~~~~

Another solution is to drop 'const' from the arguments, and rely on
the proper argument deduction by the compiler:
~~~~~~~~~~~~~~~~~
#include <stdlib.h>

template<class T1, class T2, class T3>
void add(T1* p1, T2* p2, T3* p3, size_t n)
{
while (n-- 0)
p3[n] = p1[n] + p2[n];
}

template<class T1, class T2, class T3>
void add(T1* p1, T2 v2, T3* p3, size_t n)
{
while (n-- 0)
p3[n] = p1[n] + v2;
}

void foo(const int *pci, const short *pcs, size_t n)
{
long *pl = new long[n];
add(pci, pcs, pl, n);
delete[] pl;
}

int main ()
{
int a[10];
short b[10];
long c[10];
add(a, b, c, 10);
add(a, 'b', c, 10);

foo(a, b, 10);

return 0;
}
~~~~~~~~~~~~~~~~~

Now, in this case there are three versions of 'add' functions
generated from those two templates, two from 'main' and one more
from 'foo'. Those in 'main' don't have 'const' in any of 'Tx',
and the one generated from the call in 'foo' has 'const' as part
of 'T1' and 'T2'. That should be acceptable, though.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Sep 28 '06 #5

P: n/a

am******@gmail.com wrote:
That's because the second function is more specialized than the first
function and the partial ordering rules come into the picture.
Basically in the first one T2 is deduced to be an int
and in the second case T2 is deduced to be an int*...

and if you use substitution rules governed by the partial ordering
mechanism, the second one is more specialized.
What I understant is different from you. The first one is more
specialized if both are allowable for a funcation call. For my calling
case, the second one doesn't match before implicit conversion. So the
compilor choose the second one.

Am I right?

Thanks,

Shuisheng

Sep 29 '06 #6

This discussion thread is closed

Replies have been disabled for this discussion.