argument deduction for function template

Discussion in 'C++' started by vectorizor, Jun 21, 2007.

  1. vectorizor

    vectorizor Guest

    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
     
    vectorizor, Jun 21, 2007
    #1
    1. Advertising

  2. vectorizor wrote:
    > 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
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Jun 21, 2007
    #2
    1. Advertising

  3. vectorizor

    Zeppe Guest

    Victor Bazarov wrote:
    > vectorizor wrote:
    >> 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
     
    Zeppe, Jun 21, 2007
    #3
  4. Zeppe wrote:
    > Victor Bazarov wrote:
    >> vectorizor wrote:
    >>> 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
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Jun 21, 2007
    #4
  5. On 2007-06-21 16:14, vectorizor wrote:
    > 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?

    --
    Erik Wikström
     
    =?ISO-8859-1?Q?Erik_Wikstr=F6m?=, Jun 21, 2007
    #5
  6. vectorizor

    vectorizor Guest

    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 #####
     
    vectorizor, Jun 21, 2007
    #6
  7. vectorizor wrote:
    > 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
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Jun 21, 2007
    #7
  8. vectorizor

    vectorizor Guest

    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
     
    vectorizor, Jun 21, 2007
    #8
  9. vectorizor wrote:
    > 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!


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

    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Jun 21, 2007
    #9
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    3
    Views:
    4,351
  2. Peng Yu

    Template argument deduction

    Peng Yu, Apr 16, 2005, in forum: C++
    Replies:
    1
    Views:
    509
    Mike Wahler
    Apr 16, 2005
  3. Bart Samwel
    Replies:
    14
    Views:
    811
    Bart Samwel
    Apr 22, 2005
  4. George
    Replies:
    4
    Views:
    412
    George
    Jan 13, 2006
  5. Tobias Müller
    Replies:
    12
    Views:
    501
    Nobody
    Dec 15, 2011
Loading...

Share This Page