CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 8 of 8
  1. #1
    Join Date
    Jul 2005
    Posts
    1,030

    A question regarding argument deduction of function template and class template

    When we use a function template, we use a function template like a regular function, for example,
    Code:
    template<class T>
    void foo(T t1, T t2)
    {
    }
    
    foo(1,3);
    Based on the arguments passed to foo, the compiler can deduct the type T. But on the other hand, when we use a class template, we always need to specify the type, for example,
    Code:
    template<class T>
    struct sum
    {
    	static void foo(T t1, T t2)
    	{
    	}
    };
    sum<int>::foo(1,3);
    Here we can't call sum::foo(1,3), otherwise we get compiler errors. My question is why the compiler can't deduct the type based on the arguments passed to foo? In addition, if we call function template foo like this,
    Code:
    foo(1, '3');
    Then we get compiler errors. We need to specify the type like foo<int>(1.'3'). Since '3' can be always treated as integer, why we need to specify the type here? Thanks.

  2. #2
    Join Date
    Apr 1999
    Posts
    27,449

    Re: A question regarding argument deduction of function template and class template

    Quote Originally Posted by LarryChen View Post
    Here we can't call sum::foo(1,3), otherwise we get compiler errors.
    A template class only starts to live when it is instantiated. That example you have doesn't instantiate the class template.

    Regards,

    Paul McKenzie

  3. #3
    Join Date
    Jul 2005
    Location
    Netherlands
    Posts
    2,042

    Re: A question regarding argument deduction of function template and class template

    Quote Originally Posted by LarryChen View Post
    when we use a class template, we always need to specify the type, for example,
    Code:
    template<class T>
    struct sum
    {
    	static void foo(T t1, T t2)
    	{
    	}
    };
    sum<int>::foo(1,3);
    Here we can't call sum::foo(1,3), otherwise we get compiler errors. My question is why the compiler can't deduct the type based on the arguments passed to foo?
    That's because first the compiler must look up the name 'foo' before it can perform overload resolution. If it doesn't know in which scope to look for the identifier foo, then it can't jump ahead to the next step.
    You could have specialized sum like so
    Code:
    template <class T>
    struct sum {
        static void foo(T, T);
    };
    template <>
    struct sum<int> {
        static void foo(double, double)
    };
    template <>
    struct sum<double> {
        static void foo(int, int);
    };
    So which function should be called when you call sum::foo(1, 3)?
    Quote Originally Posted by LarryChen View Post
    In addition, if we call function template foo like this,
    Code:
    foo(1, '3');
    Then we get compiler errors. We need to specify the type like foo<int>(1.'3'). Since '3' can be always treated as integer, why we need to specify the type here? Thanks.
    Why should the char be converted to an int, but not the int (first parameter) to a char?
    Cheers, D Drmmr

    Please put [code][/code] tags around your code to preserve indentation and make it more readable.

    As long as man ascribes to himself what is merely a posibility, he will not work for the attainment of it. - P. D. Ouspensky

  4. #4
    Join Date
    Jul 2005
    Posts
    1,030

    Re: A question regarding argument deduction of function template and class template

    Quote Originally Posted by Paul McKenzie View Post
    A template class only starts to live when it is instantiated. That example you have doesn't instantiate the class template.

    Regards,

    Paul McKenzie
    So you meant sum::foo(1,3) isn't really instantiated? But why simply calling function template foo(1,3) in my example works without specifying the type? On the other hand, we must specify the type for template class in order to instantiate it like sum<int>::foo(1,3)?

  5. #5
    Join Date
    Jul 2005
    Posts
    1,030

    Re: A question regarding argument deduction of function template and class template

    Quote Originally Posted by D_Drmmr View Post
    That's because first the compiler must look up the name 'foo' before it can perform overload resolution. If it doesn't know in which scope to look for the identifier foo, then it can't jump ahead to the next step.
    You could have specialized sum like so
    Code:
    template <class T>
    struct sum {
        static void foo(T, T);
    };
    template <>
    struct sum<int> {
        static void foo(double, double)
    };
    template <>
    struct sum<double> {
        static void foo(int, int);
    };
    So which function should be called when you call sum::foo(1, 3)?

    Why should the char be converted to an int, but not the int (first parameter) to a char?
    So you meant if I call foo<int>(1, '3'), then the compiler knows that '3' will be converted to integer? If I call foo(1, '3'), the compiler doesn't know whether 1 should be converted to char or '3' should be converted to integer?

  6. #6
    Join Date
    Jul 2005
    Location
    Netherlands
    Posts
    2,042

    Re: A question regarding argument deduction of function template and class template

    Quote Originally Posted by LarryChen View Post
    So you meant if I call foo<int>(1, '3'), then the compiler knows that '3' will be converted to integer? If I call foo(1, '3'), the compiler doesn't know whether 1 should be converted to char or '3' should be converted to integer?
    When you explicitly instantiate the template, the compiler does not have to deduce the template argument. Calling foo<int> is like calling a non-template function and the compiler can perform implicit conversions.
    But when template argument deduction is involved, the compiler will not perform any implicit conversions of function arguments. Consider
    Code:
    template <class T>
    void foo(T, const T*);
      
    struct S
    {
      operator const char* () const;
    };
    
    void bar()
    {
      S s;
      foo('1', "test"); // ok, foo<char> called
      foo<char>('2', s); // ok, foo<char> called, s is implicitly convertible to const char*
      foo('3', s); // error, template argument deduction failed
    }
    Cheers, D Drmmr

    Please put [code][/code] tags around your code to preserve indentation and make it more readable.

    As long as man ascribes to himself what is merely a posibility, he will not work for the attainment of it. - P. D. Ouspensky

  7. #7
    Join Date
    Apr 1999
    Posts
    27,449

    Re: A question regarding argument deduction of function template and class template

    Quote Originally Posted by LarryChen View Post
    So you meant sum::foo(1,3) isn't really instantiated? But why simply calling function template foo(1,3) in my example works without specifying the type? On the other hand, we must specify the type for template class in order to instantiate it like sum<int>::foo(1,3)?
    Because template functions and template classes are different. Just because they share the word "template" doesn't make them the same thing.

    Class templates are not as simple as a function. For example, can you specialize a template function? Can you define default template arguments to a template function as you can with a class template?

    The designers of C++ made it very clear -- for a class template, you need to specify the arguments for proper instantiation.

    Regards,

    Paul McKenzie
    Last edited by Paul McKenzie; June 21st, 2013 at 04:06 PM.

  8. #8
    Join Date
    Oct 2008
    Posts
    1,456

    Re: A question regarding argument deduction of function template and class template

    Quote Originally Posted by LarryChen View Post
    Here we can't call sum::foo(1,3), otherwise we get compiler errors.
    BTW, note that you can always wrap the static member in a free function template to "enforce" deduction, something like:

    Code:
    template<class T>
    struct sum
    {
    	static void foo(T t1, T t2)
    	{
    	}
    };
    
    template<class T>
    void foo( T t1, T t2 ) { sum<T>::foo(t1,t2); }

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured