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  
Share this Question
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 toplevel
'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 email
I do not respond to topposted replies, please don't ask  
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
 
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 mixused the float and double type in our team
project.  
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 mixused 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 email
I do not respond to topposted replies, please don't ask  
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   This discussion thread is closed Replies have been disabled for this discussion.   Question stats  viewed: 1429
 replies: 5
 date asked: Sep 28 '06
