cplusplus / CWG

Core Working Group
23 stars 7 forks source link

CWG2873 [expr.unary] Can built in address of operator take a function template with default parameter as its operand #517

Open ranaanoop opened 3 months ago

ranaanoop commented 3 months ago

Full name of submitter: Anoop Rana

Reference (section label): [expr.unary]

Link to reflector thread (if any): https://cplusplus.github.io/CWG/issues/2608.html

Issue description:

Consider the following program that shows implementation divergence.

#include <type_traits>

template<typename T = int> void func()
{
}
template<typename T> void bar(T)
{

}
int main()
{
    bar(&func); //gcc compiles this but not clang and msvc

    auto i = &func; //same behavior: gcc compiles but not clang and msvc
} 

As we can see gcc accepts both statements bar(&func); as well as auto i =&func; but clang and msvc rejects both of those statements. CWG 2608 allowed the omission of empty template argument list when the template has default parameters(of all of its parameters). Does that also allow the above program to be well-formed?

In particular, expr.unary says:

The operand of the unary & operator shall be an lvalue of some type T. The result is a prvalue.

  • If the operand is a qualified-id naming a non-static or variant member m of some class C, other than an explicit object member function, the result has type “pointer to member of class C of type T” and designates C​::​m.
  • Otherwise, the result has type “pointer to T” and points to the designated object ([intro.memory]) or function ([basic.compound]). If the operand names an explicit object member function ([dcl.fct]), the operand shall be a qualified-id.

Now, the first bullet doesn't apply here because func is not a qualified-id. And also the second bullet doesn't apply for the function template because the result would be a pointer to T but func is a template not a type. That is, the second bullet doesn't apply because the operand of & here is a template and not an lvalue of some type T.

So [expr.unary] seems to disallow the program. What is the correct behavior and intention here. It should be made clear whether the second bullet somehow applies so that we func can be used as an lvalue of type func<int>.

jensmaurer commented 3 months ago

CWG2873

AlanVoore commented 3 months ago

CWG2873 seems to mention two different issues. First is that if templates are ignored as per [over.over#3]. The second issue is whether template argument deduction considers default template arguments.

Wouldn't it be more clear if each core issue has a separate CWG? I mean the more issues a CWG has, the more time and effort(and carefullness) it will take to resolve it. @jensmaurer I get that the issue might be related but still.

jensmaurer commented 3 months ago

I see your point. In the interest of efficient handling by CWG, I still feel a single issue is better for now.

I mean the more issues a CWG has, the more time and effort(and carefullness) it will take to resolve it.

This argument fails my reality check.

lprv commented 3 months ago

As I understand it, in both examples presented in the issue, f's parameter is a non-deduced context per [temp.deduct.type]/5.6.3, and that causes the call to be ill-formed (rather than anything to do with &g in particular).

This example should work, I think, but is still rejected by implementations:

void g(int);
void g(auto);

decltype(&g) p;

BTW, since placeholder type deduction is specified in terms of template argument deduction for a function call, similar reasoning can be applied to a declaration like auto p = &g; (as seen in CWG2572).

jensmaurer commented 3 months ago

Ack. Added to the description of the issue.