6

Here is the corresponding question, what I want to know is, Is it possible to bring global function into the overload resolution with member function?

I tried in 2 ways, but both don't work:

void foo(double val) { cout << "double\n";}

class obj {
public:
  using ::foo; // (1) compile error: using-declaration for non-member at class scope
  void callFoo() { 
    using ::foo; // (2)will cause the global version always be called
    foo(6.4); 
    foo(0); 
  }
private:
  void foo(int val) {cout << "class member foo\n"; }
};
Community
  • 1
  • 1
songyuanyao
  • 169,198
  • 16
  • 310
  • 405
  • `obj::foo` is a member function and `::foo` a free function. They don't have the same type, and one needs an instance to work on. How would you expect it to work ? – Quentin Sep 16 '14 at 08:13
  • @Quentin So they can't be processed together for overload resolution? – songyuanyao Sep 16 '14 at 08:16
  • Workarounds exist to achieve it (such as a member wrapper), but what are the semantics of such an overload ? – Quentin Sep 16 '14 at 08:17
  • @Quentin I expect there's a feature supported by the language, which support the overload resolution between member function and global function. – songyuanyao Sep 16 '14 at 08:19
  • @songyuanyao It wouldn't add anything but complexity to both the language and the program. I can't think of any real-world situations where it would be beneficial. – molbdnilo Sep 16 '14 at 08:25
  • @molbdnilo I agree. In real world name repetition is confused. – songyuanyao Sep 16 '14 at 08:26

4 Answers4

5

I doubt you can make the compiler call one or the other based on the type. You can of course use a local wrapper function, something like this:

  void callFoo() { 
    foo(6.4); 
    foo(0); 
  }
private:
  void foo(double val) { ::foo(val); }

The wrapper function should nicely inline into nothing, so there is no actual overhead when compiled with optimisation.

Or don't call the member and the global function the same name, which makes life a whole lot easier!

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
2

What it appears you are trying to do is use the parameter type to choose the correct overload, and to bring the external foo into your class or member function.

Bringing it into the class is easy. You just declare another overload as a class member that forwards to the external one.

Bringing into the function is tricky but can be done by use of helper functions e.g. fooCaller( double ) and fooCaller( int ) which you can call from callFoo.

If you don't want to expose these to the external user, i.e. hide them away in the cpp file, it can be done but is trickier, due to the fact that foo in your class is private. You would have to have your callFoo function pass in the private function as a member function to "call" for the int overload.

CashCow
  • 30,981
  • 5
  • 61
  • 92
2

This is plain old unqualified name lookup, specified in §3.4.1 [basic.lookup.unqual]:

1 In all the cases listed in 3.4.1, the scopes are searched for a declaration in the order listed in each of the respective categories; name lookup ends as soon as a declaration is found for the name. If no declaration is found, the program is ill-formed.

8 For the members of a class X, a name used in a member function body, in a default argument, in an exception-specification, in the brace-or-equal-initializer of a non-static data member (9.2), or in the definition of a class member outside of the definition of X, following the member’s declarator-id, shall be declared in one of the following ways:

  • before its use in the block in which it is used or in an enclosing block (6.3), or
  • shall be a member of class X or be a member of a base class of X (10.2), or
  • if X is a nested class of class Y (9.7), shall be a member of Y, or shall be a member of a base class of Y (this lookup applies in turn to Y’s enclosing classes, starting with the innermost enclosing class), or
  • if X is a local class (9.8) or is a nested class of a local class, before the definition of class X in a block enclosing the definition of class X, or
  • if X is a member of namespace N, or is a nested class of a class that is a member of N, or is a local class or a nested class within a local class of a function that is a member of N, before the use of the name, in namespace N or in one of N’s enclosing namespaces.

Note first that name lookup stops as soon as a declaration is found. So if you have using ::foo; in callFoo(), lookup for foo will end there and never touch the second bullet point; if you don't have it, lookup for foo will find the member foo() at the second bullet point and never search elsewhere. The way unqualified name lookup is specified means that you will either find class members or non-class-members, but never both.

This is also noted in §13.1.1.1 [over.call.func]/p3:

In unqualified function calls, the name is not qualified by an -> or . operator and has the more general form of a primary-expression. The name is looked up in the context of the function call following the normal rules for name lookup in function calls (3.4). The function declarations found by that lookup constitute the set of candidate functions. Because of the rules for name lookup, the set of candidate functions consists (1) entirely of non-member functions or (2) entirely of member functions of some class T. In case (1), the argument list is the same as the expression-list in the call. In case (2), the argument list is the expression-list in the call augmented by the addition of an implied object argument as in a qualified function call.


A using-declaration at class scope must name a base class member (§7.3.3 [namespace.udecl]/p3):

In a using-declaration used as a member-declaration, the nested-name-specifier shall name a base class of the class being defined.

T.C.
  • 133,968
  • 17
  • 288
  • 421
  • Why can not use using-declaration for non-member at class scope? I think which can make it possible to find class members or non-class-members at same scope. – songyuanyao Sep 16 '14 at 09:40
1

You cannot do that probably because member functions has different signature visible by compiler, which is

void foo(double)

vs

void obj::foo(int)
Rafal Mielniczuk
  • 1,322
  • 7
  • 11