4

3.4 [basic.lookup]/p1

Overload resolution (13.3) takes place after name lookup has succeeded.

void g(long);

void g(int, int);

template<class T> void f() { g(0); }

void g(int, int = 0) {}

int main(){
    f<int>();
}

gcc compiles succeed, clang faild.

When does overload resolution of non-dependent name take place, in definition context or point of instantiation? Or both are right?

Community
  • 1
  • 1
stackcpp
  • 1,275
  • 7
  • 15

2 Answers2

2

In both context.

[temp.res] 14.6\8

If a hypothetical instantiation of a template immediately following its definition would be ill-formed due to a construct that does not depend on a template parameter, the program is ill-formed; no diagnostic is required. If the interpretation of such a construct in the hypothetical instantiation is different from the interpretation of the corresponding construct in any actual instantiation of the template, the program is ill-formed; no diagnostic is required.

[temp.nondep] 14.6.3\1

Non-dependent names used in a template definition are found using the usual name lookup and bound at the point they are used.

So both compilers are right.

  • According to 14.6\8 the example code is ill-formed, no diagnostic is required. But my question is valid, is there words in standard said about it? Both context are right? – stackcpp Dec 08 '15 at 13:50
  • The template has different interpretations depending on context. So that is an ill-formed template, but GCC allows you to use it, even it is... dangerous! – Eugene Zavidovsky Dec 08 '15 at 13:55
  • Which version of the standard are you quoting? No such wording in my copies of the drafts. – n. m. could be an AI Dec 08 '15 at 14:10
  • 1
    @Eugene Zavidovsky I get it. Overload resolution takes place in both contexts, and the result must be same, if not, the program is ill-formed; no diagnostic is required. – stackcpp Dec 08 '15 at 14:14
  • @n.m. You can find them in n4527. – stackcpp Dec 08 '15 at 14:16
  • Yeah, and there is another rule for it, see [temp.point] 14.6.4.1\8 – Eugene Zavidovsky Dec 08 '15 at 14:16
  • Yep, looks like a new wording in C++1xyzwhatever. A note below even explicitly addresses the case of default arguments. I wonder how the example in 14.6.3 is still valid when this wording is in effect, and why gcc in `-std=c++11` mode does what it does. – n. m. could be an AI Dec 08 '15 at 15:05
  • @n.m. I think, the example is like a reminder for brevity. If there was not `h++` there, the program would be well-formed. But then it would be ill-formed, if there would be actual (explicit or implicit) instantiation for `Z::f()`. But the implementation is not required to provide a diagnostic anyway... – Eugene Zavidovsky Dec 08 '15 at 16:30
  • The example is unchanged since C++11 or possibly before. It did make perfect sense before the wording in question was inserted. Now it's dubious at best. Is the "calls g(double)" remark still valid? Should it be replaced with "ill-formed"? The example is not intended to be a complete program, each line illustrates different aspects of the standard, and is "valid" or "invalid" independently of other lines, so `h++` is irrelevant here. – n. m. could be an AI Dec 08 '15 at 16:50
  • This is [CWG 1950](http://wg21.cmeerw.net/cwg/issue1850), cc @n.m. This wording is a result of an existing implementation variance. n.m.: That the example now seems invalid seems to be either an oversight or an unintended consequence, so why don't ask this on std-discussion? – dyp Dec 09 '15 at 09:27
  • @dyp Looks like an unintended consequence to me. Not a member there, for a number of reasons. – n. m. could be an AI Dec 09 '15 at 09:37
  • @dyp Unless the intention is to dispose of the two-phase lookup entirely. I could understand that. – n. m. could be an AI Dec 09 '15 at 09:41
  • 1
    @n.m. Not sure what you mean with "not a member there". If you don't want to post a question there, I'll do it later. (It's a fancy GUI on top of an old-fashioned mailing list, so membership is not required for posting or even subscribing.) – dyp Dec 09 '15 at 09:43
  • The more interesting question is when the *name* isn’t dependent (*e.g.*, because it’s qualified) but an argument is type-dependent. – Davis Herring May 30 '19 at 22:47
0

If my understanding of the lookup rules are correct, then since g() is a non-dependent name, the overload set won't be added to in phase 2. Therefore the only choice for g(0) at the point of definition is g(long), and Clang is correct.

I would certainly naively expect only g(long) to be considered given the ordering of the definitions, but then again the C++ standard isn't always intuitive when templates are involved...

Tristan Brindle
  • 16,281
  • 4
  • 39
  • 82