c++templateslanguage-lawyerfriendfriend-function

Redefinition error when defining friend function inside class template


I am learning friend declarations in C++ using the books listed here. So after reading, to test my understanding of the concept, i wrote the following program whose output i am unable to understand:

template<typename T>
struct Name
{
  
  friend void anotherFeed(int x)//anotherFeed is implicitly inline and its definition is generate only when we use this nonmember function so why are we getting error at instiantiation?
  {
  }
 
};
int main()
{
    Name<int> s;
    Name<double> p;//error here. My question is that this is instiantiation of the class template Name<double> and not a call to anotherFeed so why do we get error here?
}

The above program give the following error:

error: redefinition of ‘void anotherFeed(int)’

This is my current understanding:

  1. The friend non-member function anotherFeed(int) is implicitly inline.
  2. Even if anotherFeed(int) is inline, we cannot define the same function(doesn't matter inline or not) in the same translation unit.
  3. The definition of anotherFeed(int) is generated only when we use/call this function just like for a nontemplate member function of a class template.

My question is that: Assuming that my understanding(the above 3 points) are correct, since i have not called/used anotherFeed so its definition should not be generated and we should not get the redefinition error at the time of creating an instance of the class template. Only when we call anotherFeed using those instances, we should get the redefinition error. So why do we get error at the time of creating class template's instance. Is there anything wrong in any of the above 3 points.

Summary

I read that the definitions for these functions(non template member functions and friend non template functions) are instantiated only when used. That is,

Name<int> s;    
Name<double> p; //this should work in principle because this does not instantiate the definition of anotherFeed(int)

But this doesn't happen. Why/How?


Solution

  • This issue is addressed here.

    However, for the purpose of determining whether an instantiated redeclaration is valid according to [basic.def.odr] and [class.mem], a declaration that corresponds to a definition in the template is considered to be a definition.

    So even though there is no actual instantiation of the definition of anotherFeed(int) in your program, the compiler is still required to diagnose multiple definitions within the same translation unit as if the definition had been instantiated every time the declaration were instantiated.

    And so when you wrote:

    Name<double> p; //instantiate a declaration of anotherFeed(int) for the second time. 
    

    The above statement, instantiate a redeclaration of anotherFeed(int) and since this declaration corresponds to a definition, according to the quoted statement at the beginning of my answer you get the redefinition error.