The most unpleasant friend? Friendship with a special free function template causes a compilation error (when the method is overloaded)

the code

I reduced the problem to this example (inserted as one unit to facilitate compilation)

/// \brief The free-function template, /// which is overloading a method with the same name in AbstractA below. template <class T> inline const T overloadedMethod(const T& lhs, const T& rhs) { return T(lhs.value+rhs.value); } /// \brief AbstractA class class AbstractA { public: AbstractA (int aVal): value(aVal) {} inline const AbstractA overloadedMethod(const AbstractA &rhs) const { return AbstractA(value+rhs.value); } protected: int value; }; /// \brief A class, deriving from AbstractA, /// and friending the free-function template. class A : public AbstractA { friend const A overloadedMethod <A>(const A& lhs, const A& rhs); /// This one gives me compilation error //template<class T> friend const T overloadedMethod(const T& lhs, const T& rhs); /// This one would be okay public: A (int aVal): AbstractA(aVal) {} }; int main() { A a1(1), a2(2); overloadedMethod(a1, a2); return 0; } 

More details

Basically, the compilers I tried (VS 2010 and g ++ 4.7.2) give me an error in the line

 friend const A overloadedMethod <A>(const A& lhs, const A& rhs); 

They seem to think that I am declaring a data member named overloadedMethod.

A compilation error does not occur if:

  • I provide a non-specialized version of a free function template as a friend (commented line of code)
  • I remove the overloadedMethod () member function from the AbstractA class

Questions

I cannot explain this langage behavior, so my questions are:

  • What is the C ++ rule that leads to this error? (Why do compilers think I'm declaring a data member here?)
  • Do you know that this is a guarantee? (I'm especially interested to know why it works if I remove overloadedMethod () from the AbstractA class. Or is it UB?)
+4
source share
1 answer

First of all, the basic premise of your friend announcement is:

[C++11: 14.5.4/1]: A friend of a class or class template can be a function template or class template, specializing in a function template or class template, or a regular (non-template) function or class. To declare a friend function that is not a template declaration:

  • if the friend’s name is a qualified or unqualified template identifier, the friend’s declaration refers to the specialization of the function template , otherwise
  • if the friend’s name is a qualified identifier, and the corresponding non-template function is in the specified class or namespace, the friend’s declaration refers to this function, otherwise
  • if the friend’s name is a qualified identifier and the corresponding function template is in the specified class or namespace, the friend’s declaration refers to the derived specialization of this function template (14.8.2.6), otherwise
  • the name must be an unqualified identifier declaring (or overriding) a regular (non-template) function.

[Example:

 template<class T> class task; template<class T> task<T>* preempt(task<T>*); template<class T> class task { friend void next_time(); friend void process(task<T>*); friend task<T>* preempt<T>(task<T>*); template<class C> friend int func(C); friend class task<int>; template<class P> friend class frd; }; 

[..]> end of example]

You may run into problems because the name overloadedMethod from the base class hides the global one - regardless of the other argument list and the fact that the base name is not a template:

[C++11: 3.4.1/9]: search for the name of the name used in the definition of a friend function (11.3) defined in a string in the class that provides friendships should be performed as described for searching in the definitions of member functions. If the friend function is not defined in the class that provides the friendship, the name search in the friend function definition must be performed as described for the search in the function definitions of the namespace member.

[C++11: 3.4.1/10]: In a friend declaration, naming a member function, the name used in the function declarator, and not part of the template argument in the identifier identifier, is first looked up within the element as a class of functions (10.2) . If it is not found or if the name is part of the template argument in the identifier identifier, the search looks as described for unqualified names in the definition of the class that provides friendship.

In this case, the sentence "if it is not found" never starts.

In GCC 4.8.1, this will result in the following diagnostics :

error: field 'overloadedMethod is an incomplete type

I am sure that the specific content of this diagnostic is a bit erroneous - you basically confused the devil from your compiler by applying the template-parameter-list <A> to what it does not consider a template.

You cannot fix this, even by defining a friend declaration :

 friend const A ::overloadedMethod<A>(const A& lhs, const A& rhs); 

The following is done:

 friend auto ::overloadedMethod<A>(const A&, const A&) -> const A; 

But I think this is actually a compiler error based on the above rules.

+4
source

Source: https://habr.com/ru/post/1495700/


All Articles