Bug 5458 - address of overloaded template function as argument for template
Summary: address of overloaded template function as argument for template
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 3.0.3
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: rejects-valid
: 13947 17071 17208 17683 33004 (view as bug list)
Depends on:
Blocks:
 
Reported: 2002-01-22 16:26 UTC by kenelson
Modified: 2019-12-18 07:15 UTC (History)
15 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail: 2.95.3, 3.0.4, 3.2.3, 3.3.3, 4.0.0, 4.1.0, 4.2.0
Last reconfirmed: 2005-12-11 21:42:44


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description kenelson 2002-01-22 16:26:01 UTC
While attempting to use the std function ptr_fun on an overloaded function (sin), I found the compiler would fail if <complex> was included.  This traced to an error in the lookups of functions.  

Apparently, you can use template specifiers to choose
the overload only when a templated version of the 
function has not been encountered.  I boiled all of the 
headers down to the following example.  
ptr_fun<double>(&foo) only works if there is no
complex<T> version declared.  I verified this was 
valid code on HPUX compilers, but do not have access to 
the standard to clarify code is proper completely.

Example program generates incorrect error message.

kenelson:/tmp> g++-3 ptr_fun.cc 
ptr_fun.cc: In function `int main()':
ptr_fun.cc:7: no matching function for call to `ptr_fun(<unknown type>)'

Release:
g++ version 3.0.3

Environment:
All (platform independent)

How-To-Repeat:
#include <complex>
template <class T> std::complex<T> foo(std::complex<T>) {}
void foo(int) {}
float foo(float) {}
template <class T_arg, class T_result>
void ptr_fun(T_result (*f)(T_arg)) {}
main() { ptr_fun<float>(foo);   }
Comment 1 Nathan Sidwell 2002-04-25 07:44:10 UTC
State-Changed-From-To: open->analyzed
State-Changed-Why: yup
Comment 2 Andrew Pinski 2004-01-31 19:06:59 UTC
Here is a simple testcase:
template <class T> class vector{};
template <class T> vector <T> foo(vector <T>) {}
void foo(int) {}
float foo(float) {}
template <class T_arg, class T_result>
void ptr_fun(T_result (*f)(T_arg)) {}
main() { ptr_fun<float>(foo);   }
Comment 3 Andrew Pinski 2004-01-31 19:08:52 UTC
*** Bug 13947 has been marked as a duplicate of this bug. ***
Comment 4 Andrew Pinski 2004-05-15 21:27:43 UTC
*** Bug 15469 has been marked as a duplicate of this bug. ***
Comment 5 Andrew Pinski 2004-08-18 02:23:33 UTC
*** Bug 17071 has been marked as a duplicate of this bug. ***
Comment 6 Wolfgang Bangerth 2004-08-18 12:58:43 UTC
PR 17071 has this very nice and clean testcase.  
-------------- 
int foo (int); 
template <class T> T foo (T, T); 
 
template <class T, class U> int bar (T, U); 
 
int main () 
{ 
    bar (0, &foo); 
} 
--------------------- 
 
W.  
Comment 7 Wolfgang Bangerth 2004-08-27 13:27:07 UTC
*** Bug 17208 has been marked as a duplicate of this bug. ***
Comment 8 Andrew Pinski 2004-09-26 20:56:32 UTC
*** Bug 17683 has been marked as a duplicate of this bug. ***
Comment 9 Andrew Pinski 2006-08-21 17:13:05 UTC
*** Bug 28793 has been marked as a duplicate of this bug. ***
Comment 10 Václav Haisman 2006-10-09 14:16:05 UTC
Shouldn't the "Known to fail" field get all the versions from its duplicates copied? Maybe that is why this rejects-valid bug is still not fixed even though most other rejects-valid bugs get a lot of attention and get fixed usually pretty fast, IMHO.

2.95.3 3.0.4 4.0.0 4.1.0 4.2.0 3.3.3 3.2.3
Comment 11 Andrew Pinski 2007-08-06 13:58:37 UTC
*** Bug 33004 has been marked as a duplicate of this bug. ***
Comment 12 Rodolfo Schulz de Lima 2007-08-06 14:18:55 UTC
This is an yet simpler case where this bug shows up:

template <class T> void foo(T);
void foo(int);

void bar()
{
    &foo;
}

i686-pc-linux-gnu-g++-4.2.1 fails with:

teste.cpp: In function ‘void bar()’:
teste.cpp:6: error: statement cannot resolve address of overloaded function
Comment 13 Václav Haisman 2008-01-07 20:47:24 UTC
This still fails in 4.3.0. Know to fail sorted and without duplicates should read: 2.95.3 3.0.4 3.2.3 3.3.3 4.0.0 4.1.0 4.2.0 4.3.0
Comment 14 Jason Merrill 2009-11-25 02:55:25 UTC
I'm not sure the standard actually says that this is well-formed, though it seems reasonable to me.

13.4/2: If the name is a function template, template argument deduction is done (14.9.2.2), and if the argument deduction succeeds, the resulting template argument list is used to generate a single function template specialization, which is added to the set of overloaded functions considered.

14.9.2.2: The function template’s function type and the specified type are used as the types of P and A, and the deduction is done as described in 14.9.2.5.

It's not entirely clear that there is a "specified type" for this kind of two-way deduction.  EDG also rejects this.
Comment 15 Joseph Garvin 2010-01-21 18:38:33 UTC
I'm not sure what the standard says, but conceptually, if you only provide a template generic template foo, with no non-templated foo defined, then instantiations of foo are *never* 'overloaded.' If I have:

template<int n>
void foo() {}

Then foo<3> is a distinct function from foo<2>. It doesn't make sense to refer to foo as overloaded (unless there is also a non-templated foo defined). foo<3> has a single unique address, there is no ambiguity. Automatically considering it an overloaded function (as I suspect GCC must be doing internally) leads to a confusing error when compiling this snippet:

#include <iostream>

template<int n>
void foo() {}

int main()
{
	&foo;
}

You get the same error about not being able to resolve foo because it's overloaded. But foo isn't a function at this point. It's a template. And no template parameters have been filled in. I should get an error about expecting angle brackets.
Comment 16 Jonathan Wakely 2010-01-21 19:00:04 UTC
Shouldn't it get the same error as for this case?

template<class T>
T foo() { return T(); }

int main()
{
        &foo;
}

That example can be made valid like so:

        int (*pf)() = &foo;

Which demonstrates that the angle brackets are not necessary, *if* the compiler can determine which specialisation is intended.  So the "cannot resolve address of overloaded function" error is arguably correct.
Comment 17 Jason Merrill 2010-01-21 19:09:14 UTC
We describe a template as overloading itself since it represents any number of actual functions.
Comment 18 Jason Merrill 2019-12-18 07:15:05 UTC
The compiler is following the standard.  C++11 and up say,

When P is a function type, pointer to function type, or pointer to member function type:
— If the argument is an overload set containing one or more function templates, the parameter is treated as a non-deduced context.
— If the argument is an overload set (not containing function templates), trial argument deduction is attempted using each of the members of the set. If deduction succeeds for only one of the overload set members, that member is used as the argument value for the deduction. If deduction succeeds for more than one member of the overload set the parameter is treated as a non-deduced context.

So indeed, adding a function template to the overload set means no deduction is done, according to the first bullet.