argument deduction for function template

V

vectorizor

Hi all,

I have a slight problem with the usage of function templates. It shoud
be really easy for you guys to explain me what's wrong.

I have one base class and 2 derived classes:

/*code*/
template <typename T> struct Image {...};
template <typename T> struct GrayImage : public Image<T> {...};
template <typename T> struct ColorImage : public Image<T> {...};
/*code*/

I am now trying to write a funtion to process images. The definition
is:

/*code*/
template <typename T, typename U> void func1(ColourImage<U> &input,
GrayImage<T> &output) {...}
/*code*/

Now I am tring to call this function as follow

/*code*/
GrayImage<f32> gray, tmp;
ColourImage<u8> color;
// ....
func1(color, gray);
/*code*/

When I try to compile that, the Visual Studio compilers complains that
"template parameter 'T' is ambiguous". Why is that? I do not
understand why.
It works though if I specify the template arguments explicitly though,
as follow

/*code*/
func1<f32, u8>(color, gray);
/*code*/

But ideally, I would like not to specify that. The thing that really
puzzles me is that I do not need to do that for a very similar
function.

/*code*/
template <typename T> void test(GrayImage<T> &input, GrayImage<T>
&output) {...}
// ...
GrayImage<f32> gray, tmp;
// ...
test(gray, tmp);
/*code*/

This works just fine. So what is the problem with the previous
function?!

Thanks in advance

Alex
 
V

Victor Bazarov

vectorizor said:
Hi all,

I have a slight problem with the usage of function templates. It shoud
be really easy for you guys to explain me what's wrong.

I have one base class and 2 derived classes:

/*code*/
template <typename T> struct Image {...};
template <typename T> struct GrayImage : public Image<T> {...};
template <typename T> struct ColorImage : public Image<T> {...};

Note the spelling of 'ColorImage'.
/*code*/

I am now trying to write a funtion to process images. The definition
is:

/*code*/
template <typename T, typename U> void func1(ColourImage<U> &input,

Note the spelling of the type of the first argument.
GrayImage<T> &output) {...}
/*code*/

Now I am tring to call this function as follow

/*code*/
GrayImage<f32> gray, tmp;
ColourImage<u8> color;

Not the spelling of the type and the variable here. Please try to
stick to naming your things _consistently_.

This goes again toward the argument why code should NOT be typed into
the message. *Copy and paste* your code!!!
// ....
func1(color, gray);
/*code*/

When I try to compile that, the Visual Studio compilers

Which ones? VC++ 2005 seems to compile it correctly.
complains that
"template parameter 'T' is ambiguous". Why is that? I do not
understand why.

Because the compiler you're using is/are buggy?
It works though if I specify the template arguments explicitly though,
as follow

/*code*/
func1<f32, u8>(color, gray);
/*code*/

But ideally, I would like not to specify that. The thing that really
puzzles me is that I do not need to do that for a very similar
function.

/*code*/
template <typename T> void test(GrayImage<T> &input, GrayImage<T>
&output) {...}
// ...
GrayImage<f32> gray, tmp;
// ...
test(gray, tmp);
/*code*/

This works just fine. So what is the problem with the previous
function?!

No problem. But if you have to use the compiler you are using,
stick to your work-around.

V
 
Z

Zeppe

Victor said:
vectorizor said:
complains that
"template parameter 'T' is ambiguous". Why is that? I do not
understand why.

Because the compiler you're using is/are buggy?


I would guess that the code he compiled is not the same that the one in
the message.

Regards,

Zeppe
 
V

Victor Bazarov

Zeppe said:
Victor said:
vectorizor said:
complains that
"template parameter 'T' is ambiguous". Why is that? I do not
understand why.

Because the compiler you're using is/are buggy?


I would guess that the code he compiled is not the same that the one
in the message.


That's a pretty good guess. But it might also be true that the OP's
not using the latest compiler, and as I recall, VC++ v6 was *really*
bad with templates. VC++ v7.0 wasn't to much better either. The
break came at VC++ v7.1. I have no way of testing *my* interpretation
of the OP's code with any of those at this point.

V
 
?

=?ISO-8859-1?Q?Erik_Wikstr=F6m?=

Hi all,

I have a slight problem with the usage of function templates. It shoud
be really easy for you guys to explain me what's wrong.

I have one base class and 2 derived classes:

/*code*/
template <typename T> struct Image {...};
template <typename T> struct GrayImage : public Image<T> {...};
template <typename T> struct ColorImage : public Image<T> {...};
/*code*/

I am now trying to write a funtion to process images. The definition
is:

/*code*/
template <typename T, typename U> void func1(ColourImage<U> &input,
GrayImage<T> &output) {...}
/*code*/

Now I am tring to call this function as follow

/*code*/
GrayImage<f32> gray, tmp;
ColourImage<u8> color;
// ....
func1(color, gray);
/*code*/

When I try to compile that, the Visual Studio compilers complains that
"template parameter 'T' is ambiguous". Why is that? I do not
understand why.
It works though if I specify the template arguments explicitly though,
as follow

/*code*/
func1<f32, u8>(color, gray);
/*code*/

But ideally, I would like not to specify that. The thing that really
puzzles me is that I do not need to do that for a very similar
function.

/*code*/
template <typename T> void test(GrayImage<T> &input, GrayImage<T>
&output) {...}
// ...
GrayImage<f32> gray, tmp;
// ...
test(gray, tmp);
/*code*/

This works just fine. So what is the problem with the previous
function?!

Except from some ambiguity whether it's called ColourImage or ColorImage
I could find no problems and ended up with the following code from your
snippets above:

template <typename T>
struct Image
{ };

template <typename T>
struct GrayImage : public Image<T>
{ };

template <typename T>
struct ColorImage : public Image<T>
{ };

template <typename T, typename U>
void func1(ColorImage<U> &input, GrayImage<T> &output)
{ }

int main()
{
GrayImage<float> gray;
ColorImage<int> color;
func1(color, gray);
}

This compiles fine with both VC++2005 and Comeau online. Did I miss
something or is there some code you have not shown us? By the way, which
compiler are you using?
 
V

vectorizor

Hey all,

thanks for the comments. Please find attached a standalone version of
my code. Please forgive the mess, I just did a quick copy and paste of
many files.

I am compiling with VS 2005 and the latest Intel compiler.

##### CUT #####
#include <windows.h>
#include <stdio.h>
#include <math.h>

////////////////////
///// INTEGERS
////////////////////

// unsigned
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned long u32;
typedef unsigned long long u64;

// signed
typedef signed char i8;
typedef signed short i16;
typedef signed long i32;
typedef signed long long i64;




////////////////////
///// FLOATING-POINT VALUES
////////////////////

typedef float f32;
typedef double f64;




////////////////////
///// MEMORY ROUTINES
////////////////////

enum { MemoryAlignment=64};

void* AllocateMemory(size_t size)
{
return _aligned_malloc(size, MemoryAlignment);
}

void ReleaseMemory(void *memblock)
{
return _aligned_free(memblock);
}

int ComputeAlignedWidth(int width)
{
int alignment_needed = MemoryAlignment / sizeof(float);
return (int)ceil((float)width/(float)alignment_needed) *
alignment_needed;
}




////////////////////
///// CLASS DECLARATION
////////////////////


template <typename T>
struct Image
{
public: // members
// std information
int width, height, depth;

// actual width of the buffer
// buffer holding image data is padded to be a multiple
// of MemoryAlignment for optimisation purposes
int width_padded;

// dimensions helper
int firstRow, lastRow, firstCol, lastCol;

// pointer to the image data
T* data;

public: // methods
// ctor
Image():
width(0),height(0),depth(0),
width_padded(0),
firstRow(0), lastRow(0), firstCol(0), lastCol(0),
data(NULL)
{
}

// dtor
~Image()
{
}

// memory management
void Allocate() { data =
static_cast<T*>(AllocateMemory(width_padded*height*depth*sizeof(T)));}
void Release () { ReleaseMemory(data);}

// pixel access
// virtual T& operator() (int row, int col)

// dimensions management
void SetDimensions(int h, int w, int d){
height = h;
width = w;
depth = d;
width_padded = ComputeAlignedWidth(width);
firstRow = 0;
firstCol = 0;
lastRow = height-1;
lastCol = width-1;
}

// size information
int GetTotalSize(bool padded=false){
if (padded) return width_padded*height*depth*sizeof(T);
else return width *height*depth*sizeof(T);
}
int GetImageSize(bool padded=false){
if (padded) return width_padded*height*depth;
else return width *height*depth;
}
int GetPlaneSize(bool padded=false){
if (padded) return width_padded*height;
else return width *height;
}

};




template <typename T>
struct GrayImage : public Image<T>
{
public: // methods
// ctor
GrayImage():
Image()
{
depth=1;
}

// pixel access
T& operator() (int row, int col)
{
return data[row*width_padded + col];
}
};




template <typename T>
struct ColourImage : public Image<T>
{
public: // definitions

enum{red=0, green=1, blue=2};
enum{r =0, g =1, b =2};

public: // methods
// ctor
ColourImage():
Image()
{
depth=3;
}

// pixel access
T& operator() (int row, int col, int channel)
{
return data[(row*width_padded + col)*3 + channel];
}
};



#define MIN(A,B) ((A < B) ? A : B)
#define MAX(A,B) ((A > B) ? A : B)
#define MAX3(R, G, B) ((((R) > (G) ? (R) : (G)) > B) ? ((R) > (G) ?
(R) : (G)) : B)


template <typename T, typename U>
void RGB2Log(ColourImage<U> &input, GrayImage<T> &buffer, bool linear,
T snr)
{
for(int row=input.firstRow ; row<=input.lastRow ; ++row){
for(int col=input.firstCol ; col<input.lastCol; ++col){
buffer(row, col) = MAX3(input(row, col,
ColourImage<U>::r),
input(row, col,
ColourImage<U>::g),
input(row, col,
ColourImage<U>::b));

}
}

return;
}

template <typename T>
void test(GrayImage<T> &input, GrayImage<T> &output)
{
for(int row=input.firstRow ; row<=input.lastRow ; ++row){
for(int col=input.firstCol ; col<input.lastCol; ++col){
output(row, col) = input(row, col)/2;
}
}
}




int main(int argc, char* argv[])
{
GrayImage<f32> gray, tmp;
ColourImage<u8> color;

gray.SetDimensions(2000, 2000, 3); gray.Allocate();
color.Allocate();
gray.SetDimensions(color.height, color.width, 1);
gray.Allocate();
tmp.SetDimensions(color.height, color.width, 1);
tmp.Allocate();

RGB2Log(color, gray, true, 1.0);
//RGB2Log<f32, u8>(color, gray, true, 1.0);

test(gray, tmp);

color.Release(); gray.Release(); tmp.Release();

return 0;
}

##### CUT #####
 
V

Victor Bazarov

vectorizor said:
Hey all,

thanks for the comments. Please find attached a standalone version of
my code. Please forgive the mess, I just did a quick copy and paste of
many files.

I am compiling with VS 2005 and the latest Intel compiler.

This is what your code should look like, distilled:
[..]
typedef float f32;
typedef unsigned char u8;

template <typename T>
struct Image
{
};

template <typename T>
struct GrayImage : public Image<T>
{
};

template <typename T>
struct ColourImage : public Image<T>
{
};

template <typename T, typename U>
void RGB2Log(ColourImage<U> &input, GrayImage<T> &buffer,
bool linear, T snr)
{
}

int main(int argc, char* argv[])
{
GrayImage<f32> gray, tmp;
ColourImage<u8> color;

RGB2Log(color, gray, true, 1.0);

Here you pass 'GrayImage<f32>' as the second argument from which
'T' is deduced as 'f32' or 'float'. _And_ you pass 1.0 (a double
literal) as the fourth argument, from which 'T' is deduced as...
'double' ! Do you not see it in the error message?

Now , if you want '1.0' to be treated as 'f32', you need to cast
it to 'f32':

RGB2Log(color, gray, true, (f32) 1.0);
}

##### CUT #####

V
 
V

vectorizor

Thanks a lot, and well spotted! I really couldn't understand, so I was
half-expecting something silly like that, but I just couldnt see it!
Do you not see it in the error message?

no, both compilers just mentioned they cowardly gave up!

Thanks again,

Alex
 
V

Victor Bazarov

vectorizor said:
Thanks a lot, and well spotted! I really couldn't understand, so I was
half-expecting something silly like that, but I just couldnt see it!


no, both compilers just mentioned they cowardly gave up!

You need a better compiler. VC++ 2005 gave something in line with
"Ambiguous template argument T, can be f32 or double".

V
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,020
Latest member
GenesisGai

Latest Threads

Top