c++referenceconst-reference

friend functions with const parameters


I got to know that to make a friend function, friend function should be explicitly declared in enclosing scope or take an argument of its class. However, this one seems to be a caveat, I am failed to understand. Why does the call to f1(99) not works?

class X { 
  public:
    X(int i) {
      std::cout << "Ctor called" << std::endl;
    }
    friend int f1(X&);
    friend int f2(const X&);
    friend int f3(X);
};
int f1(X& a) {
  std::cout << "non-const called" << std::endl;
}
int f2(const X& a) {
  std::cout << "const called" << std::endl;
}
int f3(X a) {
  std::cout << "object called" << std::endl;
}   

int main() {
  f1(99);
  f2(99);
  f3(99);
}

Solution

  • You're calling the functions with argument 99; but all the functions expect an X. 99 could convert to X implicitly, but the converted X is a temporary object and can't be bound to lvalue-reference to non-const.

    The temporary object could be bound to lvalue-reference to const (and also rvalue-reference since C++11), then f2(99); works. And it could be copied to the parameter of f3, then f3(99) works too.

    The effects of reference initialization are:

    • Otherwise, if the reference is lvalue reference to a non-volatile const-qualified type or rvalue reference (since C++11):

      • Otherwise, object is implicitly converted to T. The reference is bound to the result of the conversion (after materializing a temporary) (since C++17). If the object (or, if the conversion is done by user-defined conversion, the result of the conversion function) is of type T or derived from T, it must be equally or less cv-qualified than T, and, if the reference is an rvalue reference, must not be an lvalue (since C++11).