Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between a pointer to a standalone and a friend function

I don't understand why the following does not compile (e.g. in gcc 9.10 or MS VS C++ 2019):

class X {
  public:
    friend bool operator==(int, X const &);
};

int main() {
  2 == X();  // ok...
  static_cast<bool (*)(int, X const &)>(&operator==);  // Error: 'operator==' not defined
  return 0;
}

but the following code is compiled without any issues:

class X {
  public:
};
bool operator==(int, X const &);

int main() {
  2 == X();  // ok...
  static_cast<bool (*)(int, X const &)>(&operator==);  // OK!
  return 0;
}

My expectation is that a friend function (operator==) of X behaves as a standalone function (operator==). What I'm missing? Thanks

like image 746
Jarek C Avatar asked Aug 03 '20 08:08

Jarek C


People also ask

What is the difference between friend function and friend class?

A friend function is used for accessing the non public member of a class. A class can allow non-member function and other classes to access its own private data by making them friend A Friend class has full access of private data members of another class without being member of that class.

What is the difference between friend function and inline function?

A friend function is used to access non public members of the class. A friend function cannot be called by class object. Friend keyword is used to define the friend function. And the Inline functions are functions where the call is made to inline functions.

Does friend function have pointer?

The this pointer is an implicit parameter to all member functions. Therefore, inside a member function, this may be used to refer to the invoking object. Friend functions do not have a this pointer, because friends are not members of a class.

What is the difference between a function and a pointer?

There is a world of difference between these two. A function that returns a pointer is a function, that is to say, it is a block of code that performs some actions and returns a pointer variable that points to some data (or maybe to another function).

How does the friend operator work in C++?

It also declares a function class scope. The friend operator function takes 2 parameters in a binary operator. It then varies one parameter in a unary operator. The function will be implemented outside the class scope. But, the working and the implementation are the same as the binary operator function.

What is friend class in C++?

Friend Class is a class that can access both private and protected variables of the class in which it is declared as a friend, just like a friend function. Classes declared as friends to any other class will have all the member functions as friend functions to the friend class. Friend functions are used to link both these classes.

Are friend functions member functions?

Even though the prototypes for friend functions appear in the class definition, friends are not members functions. We can declare friend functions anywhere in a class definition, that is either in public, private or protected sections.


3 Answers

What I'm missing?

An inline friend declaration does not make the function available to ordinary name lookup.

Pay close attention to the error. It does not say that the function is of the wrong type, it simply can't find anything named operator==. This is by design.

Inline friend definitions are only found by argument dependent lookup. Ordinary lookup (such as naming the function to take its address), cannot find it. If you want the function to be available for that purpose, you must provide a namespace scoped declaration.

class X {
  public:
    friend bool operator==(int, X const &) { /* ... */ }
};

bool operator==(int, X const &);
like image 84
StoryTeller - Unslander Monica Avatar answered Oct 11 '22 20:10

StoryTeller - Unslander Monica


From the standard 11.9.3.7:

Such a function is implicitly an inline ([dcl.inline]) function if it is attached to the global module. A friend function defined in a class is in the (lexical) scope of the class in which it is defined. A friend function defined outside the class is not ([basic.lookup.unqual]).

From the standard namespace.memdef/3: (Thanks @StoryTeller)

If a friend declaration in a non-local class first declares a class, function, class template or function template the friend is a member of the innermost enclosing namespace. The friend declaration does not by itself make the name visible to unqualified lookup ([basic.lookup.unqual]) or qualified lookup ([basic.lookup.qual]). [ Note: The name of the friend will be visible in its namespace if a matching declaration is provided at namespace scope (either before or after the class definition granting friendship). — end note ] If a friend function or function template is called, its name may be found by the name lookup that considers functions from namespaces and classes associated with the types of the function arguments ([basic.lookup.argdep]). If the name in a friend declaration is neither qualified nor a template-id and the declaration is a function or an elaborated-type-specifier, the lookup to determine whether the entity has been previously declared shall not consider any scopes outside the innermost enclosing namespace.

The following doesn't work because the function is not visible in the current scope.

  static_cast<bool (*)(int, X const &)>(&operator==);  // Error: 'operator==' not defined
like image 23
Waqar Avatar answered Oct 11 '22 18:10

Waqar


The difference is that in the first snippet you only declare the operator in the scope of X, but not outside. There is no operator==(int,X const &) accesible from main. If you fix that and do declare it also outside you only get warnings:

class X {
  public:
    friend bool operator==(int, X const &);
};

bool operator==(int,X const&);    // <--

int main() {
  2 == X();  // ok...
  static_cast<bool (*)(int, X const &)>(&operator==);  // Error: 'operator==' not defined
  return 0;
}

Note however, that for both cases you do need a definition to actually call the operator.

For illustration consider that with

struct foo {
    friend void bar() { 
         std::cout << "this is a inline definition of friend funtion";
    }
};

The only way to access bar from outside foo is to add a declaration outside of foo:

void bar();
like image 29
463035818_is_not_a_number Avatar answered Oct 11 '22 20:10

463035818_is_not_a_number