Redefinition error when defining friend function inside class template

Viewed 285

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?

3 Answers

The free function

friend void anotherFeed(int x){}

is not dependent on the template parameter, hence, there is only this one free function which is defined twice in your example. Make it a forward declaration only

template<typename T>
struct Name {
    friend void anotherFeed(int x);
};

and define it outside the class definition

void anotherFeed(int x) {}

and all's well.

For a function template, its declaration can be instantiated without instantiating its definition.

This instantiates everything except the function body (more or less).

The declaration of your function is instantiated when the class is instantiated. When (and if) you actually call the function, its definition is instantiated.

I can't find the right standard quote, but apparently the compiler doesn't need to instantiate the definitions to reject the duplicate instantiated declarations.

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.

Related