Search code examples
c++templatescopy-constructorfriend-function

friend function and copy constructors


The code shown below doesn't compile when the friend function mag() is defined inside the class, but works if defined outside class (commented). I think the difference is caused by the copy constructor used to change the argument type from A to B. Can someone explain why I should define the friend function outside?

Moreover, if class B is a template class (adding template <class T> at the top), defining the friend function outside will also not work.

#include <iostream>
using namespace std;

class A {
};

class B {
public:
    B(const  A& p) {
        std::cout << "Copy/Conversion constructor" << std::endl;
    }
    friend void mag(const B& p) {
        std::cout << "Mag Inside`.\n";
    }
};
//void mag(const B& p) {
//     std::cout << "Mag Outside.\n";
//}
int main() {
    A a;
    mag(a);
    return 0;
}

Solution

  • Because the function mag is not declared in the global scope (you did defined and declared it when you made it a friend at the same time, but the declaration in it's own scope is still required).

    You need to declare it :

    class B {
    public:
        B(const  A& p) {
            std::cout << "Copy constructor" << std::endl;
        }
        friend void mag(const B& p) {
            std::cout << "Mag Inside`.\n";
        }
    };
    
    void mag(const B& p);
    

    If you call mag with a B object, Argument Dependant Lookup will look into B's scope and find the definition.

    Now if B is a template, you'll need to declare each version of mag with the appropriate parameters (and if several exist, you'll need to help the compiler to resolve ambiguities during conversions) :

    template<typename T>
    class B {
    public:
        B(const  A& p) {
            std::cout << "Copy constructor" << std::endl;
        }
    
        friend void mag(const B<T>& p) {
            std::cout << "Mag Inside`.\n";
        }
    };
    
    void mag(const B<int>& p);  // Version for B<int> declared.