Search code examples
c++language-lawyeroverload-resolutionusing-directivesusing-declaration

What's the relevance of the Note in [over.load]/1?


(You might see this question as a duplicate of this, but, to be honest, I've not really understood the matter, so I'm asking separately with my own wording.)

[over.load]/1 reads:

Not all function declarations can be overloaded. Those that cannot be overloaded are specified here. A program is ill-formed if it contains two such non-overloadable declarations in the same scope. [ Note: This restriction applies to explicit declarations in a scope, and between such declarations and declarations made through a using-declaration. It does not apply to sets of functions fabricated as a result of name lookup (e.g., because of using-directives) or overload resolution (e.g., for operator functions). — end note]

As a provisional question, am I correct to say that "This restriction" refers to the fact that "Not all function declarations can be overloaded"?

If that's the case, then I would deduce that if I create the situation that a set "of functions fabricated as a result of name lookup" exists, then those can be overloaded even if they are specified there in the list following the quoted paragraph above, because the restriction does not apply.

But what does that even mean, and how is it useful to know it?

I very well know that I can't overload function differing only in the return type, as this erroneous code demonstrates,

int f() { return 1; };
double f() { return 2; }; // compile-time error

and I also know that the same identical scenario happens if one of the two fs is in another namespace but brought in via using declaration

int f() { return 1; };
namespace n {
double f() { return 2; };
}
using n::f; // compile-time error

I think the first snippet above is an example of explicit declarations in a scope, whereas the second snippet is an example of between such declarations and declarations made through a using-declaration.

But what is an example of functions fabricated as a result of name lookup (e.g., because of using-directives)? Something like this?

int f() { return 1; };
namespace n {
double f() { return 2; };
}
using namespace n; // no error, as n::f can be seen by name lookup, but it's not actually declared here

If that's the case, what should I deduce from it? The restriction does not apply, so I can overload this 2 functions. What does it mean? Am I already overloading them as soon as I write the 5-lines snippet above? Or do I need to make a call such as auto x = f()? In that case, the call is ambiguous, though.

I really don't understand what that Note is trying to tell.


Solution

  • In your example with the using-directive, the functions are not overloaded. Overloading is defined in [over.pre]/1:

    When two or more different declarations are specified for a single name in the same scope, that name is said to be overloaded, and the declarations are called overloaded declarations. ...

    The two f's are not in the same scope, so they are not overloaded.

    However, if you attempt to call f, an overload set will be formed from the result of name lookup, and it contains both f declarations. An overload set is always fabricated; it is created when the name is used (not just declared); such fabrication can potentially bring multiple functions into the same overload set despite the fact that it would have been illegal to overload those functions with each other. The note is pointing out that it is not ill-formed to create such an overload set.

    Of course, overload resolution might be ambiguous, leading to an ill-formed program, but there are ways of using the overload set that are well-formed. For example, the following is A-OK:

    int f() { return 1; };
    namespace n {
    double f() { return 2; };
    }
    using namespace n;
    double (*fp)() = &f;