Thread: Problem with overloaded function templates

  1. #1
    Registered User
    Join Date
    Dec 2004
    Posts
    20

    Problem with overloaded function templates

    The function templates:

    Code:
    template<typename Contain1, typename Contain2,
      typename BinaryFunc>
    void testBinary(Contain1& src1, Contain1& src2, 
      Contain2& dest, BinaryFunc f) {
            transform(src1.begin(), src1.end(), src2.begin(), dest.begin(), f);
    }
    
    template<typename Contain1, typename Contain2>
    void testBinary(Contain1& src1, Contain2& src2,
      Contain2& dest, modulus<float> f) {
    	Contain1::iterator iter = src1.begin();
    	Contain2::iterator iter2 = dest.begin();
    
    	while (iter++ != src1.end())
    	    *iter2++ = 0;
    }
    The function call "testBinary(x, y, r, modulus<float>())" is rejected by the compiler for being ambigious. I thought that the compiler uses the more specialized overloaded form, which should be the 2nd one. Does someone have an idea, how I could convince the compiler to see it my way?
    Or am I wrong about the "compiler uses the more specialized version of overloaded function templates"?

    TIA

  2. #2
    Registered User
    Join Date
    Nov 2002
    Posts
    491
    Please provide us with the entire error. Copy and paste it, no paraphrasing.

  3. #3
    Registered User
    Join Date
    Dec 2004
    Posts
    20
    I hate these template error messages, terrible to read or even understand...
    Complete error text:

    Compiler: Default compiler
    Executing g++.exe...
    g++.exe "F:\Cpp\Tutorials\book2\code\C06\FunctionObjects.c pp" -o "F:\Cpp\Tutorials\book2\code\C06\FunctionObjects.e xe" -fexceptions -g3 -I"F:\Cpp\Dev-Cpp\lib\gcc\mingw32\3.4.2\include" -I"F:\Cpp\Dev-Cpp\include\c++\3.4.2\backward" -I"F:\Cpp\Dev-Cpp\include\c++\3.4.2\mingw32" -I"F:\Cpp\Dev-Cpp\include\c++\3.4.2" -I"F:\Cpp\Dev-Cpp\include" -I"F:\Cpp\customLibs" -L"F:\Cpp\Dev-Cpp\lib" -L"F:\Cpp\customLibs" -g3
    F:\Cpp\Tutorials\book2\code\C06\FunctionObjects.cp p: In function `int main()':

    F:\Cpp\Tutorials\book2\code\C06\FunctionObjects.cp p:94: error: call of overloaded `testBinary(std::vector<float, std::allocator<float> >&, std::vector<float, std::allocator<float> >&, std::vector<float, std::allocator<float> >&, std::modulus<float>)' is ambiguous
    F:\Cpp\Tutorials\book2\code\C06\FunctionObjects.cp p:35: note: candidates are: void testBinary(Contain1&, Contain1&, Contain2&, BinaryFunc) [with Contain1 = std::vector<float, std::allocator<float> >, Contain2 = std::vector<float, std::allocator<float> >, BinaryFunc = std::modulus<float>]
    F:\Cpp\Tutorials\book2\code\C06\FunctionObjects.cp p:41: note: void testBinary(Contain1&, Contain2&, Contain2&, std::modulus<float>) [with Contain1 = std::vector<float, std::allocator<float> >, Contain2 = std::vector<float, std::allocator<float> >]

    Execution terminated

  4. #4
    Nonconformist Narf's Avatar
    Join Date
    Aug 2005
    Posts
    174
    How're you calling testBinary? You also need to use typename here:
    Code:
    typename Contain1::iterator iter = src1.begin();
    typename Contain2::iterator iter2 = dest.begin();
    Just because I don't care doesn't mean I don't understand.

  5. #5
    Registered User
    Join Date
    Dec 2004
    Posts
    20
    As stated above, the call is "testBinary(x, y, r, modulus<float>())". The exact type of x,y,r shouldn't matter, but as you can see from the error message, they are all of vector<float>.

  6. #6
    Nonconformist Narf's Avatar
    Join Date
    Aug 2005
    Posts
    174
    Okay, in that case it is ambiguous because both templates are equally good choices. Now I want to know why you're doing this. modulus<float> is illegal because you can't use % on floating-point types.
    Just because I don't care doesn't mean I don't understand.

  7. #7
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    you can't use % on floating-point types.
    No, but (in C at least) you can use fmod().
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  8. #8
    Registered User
    Join Date
    Dec 2004
    Posts
    20
    Well, and why are they ambiguous?
    Quoting "Thinking in C++ Vol. 2":
    "A function template is considered more specialized than another if every possible list of arguments that matches it also matches the other, but not the other way around."

    The upper form can be called with anything that can be used as a binary function, whereas the lower form only accepts modulus<float>. So the upper form can accept every call that the lower can, but the lower cannot accept every call that the upper can. Am I missing something glaringly obvious here?

    As to the why:
    That's just an excercise from the book, where you should change some code demonstrating different algorithms with <int> containers so that it works with <float> containers. And just for the fun of it, I tried to use overloaded function templates to deal with that one call (modulus) that cannot handle floats. As you can see, the specialized form with modulus<float> just returns 0. So the why doesn't really matter, I just want to understand the ordering of function templates. Since it doesn't work as I expected .

  9. #9
    Nonconformist Narf's Avatar
    Join Date
    Aug 2005
    Posts
    174
    No, but (in C at least) you can use fmod().
    But modulus<> isn't defined to use fmod(), it's defined to use %. So the code as given won't compile even if you fix it.
    Quoting "Thinking in C++ Vol. 2":
    Yes, but how is the template function using modulus<float> more specialized than the template function using a template argument? Partial ordering will replace both with a matching type, and because all of the arguments match, both templates are equally viable and the call is ambiguous.
    Am I missing something glaringly obvious here?
    You're assuming that the compiler thinks like you do. In many cases it does the logical thing, but sometimes it decides that two functions are ambiguous when it's obvious to you which should be picked or chooses a different function than you would expect.
    Just because I don't care doesn't mean I don't understand.

  10. #10
    Registered User
    Join Date
    Sep 2005
    Posts
    2
    I think the problem is that there is a typo in the code.

    Change Contain2 to Contain1, and it should work.

    The second form is a specialization of the template and will be chosen first, but only if the argument types are the same.

    Code:
    template<typename Contain1, typename Contain2,
      typename BinaryFunc>
    void testBinary(Contain1& src1, Contain1& src2, 
      Contain2& dest, BinaryFunc f) {
            transform(src1.begin(), src1.end(), src2.begin(), dest.begin(), f);
    }
    
    template<typename Contain1, typename Contain2>
    void testBinary(Contain1& src1, Contain1& src2,
      Contain2& dest, modulus<float> f) {
    	typename Contain1::iterator iter = src1.begin();
    	typename Contain2::iterator iter2 = dest.begin();
    
    	while (iter++ != src1.end())
    	    *iter2++ = 0;
    }

    how is the template function using modulus<float> more specialized than the template function using a template argument
    It is more specialized because it only has 2 type parameters (and one specified) compared to the more general one which has 3 type parameters.


    modulus<float> is illegal because you can't use % on floating-point types
    I think the point of the specialization is to avoid this problem.

    DaveProgrammer
    Last edited by DaveProgrammer; 09-05-2005 at 10:52 AM.

  11. #11
    Registered User
    Join Date
    Dec 2004
    Posts
    20
    LOL, ouch! Thanks a lot, DaveProgrammer. I don't think I'd have ever noticed this typo... Funny how you can get fixated on what the error should be and don't see the most obvious explanation. And indeed it works... Now, at last, the compiler came to understand the wisdom of my overloaded function templates. *cough*
    Last edited by New++; 09-05-2005 at 04:04 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 4
    Last Post: 05-13-2011, 08:28 AM
  2. Compiling sample DarkGDK Program
    By Phyxashun in forum Game Programming
    Replies: 6
    Last Post: 01-27-2009, 03:07 AM
  3. Bisection Method function value at root incorrect
    By mr_glass in forum C Programming
    Replies: 3
    Last Post: 11-10-2005, 09:10 AM
  4. Replies: 6
    Last Post: 03-02-2005, 02:45 AM
  5. Replies: 5
    Last Post: 02-08-2003, 07:42 PM