There is a certain Vector2<T> class with an overloaded operator (perhaps a similar behavior with ordinary functions, but due to unpredictable behavior (more on that later) we could not reliably be verified):

 template <typename T> class Vector2 { ... template <typename> // объявляем дружественную ф-цию шаблонной friend Vector2<T> operator +(Vector2<T> const& l_v, Vector2<T> const& r_v); ... } 

I will pay attention to the form of recording a constant link - T const& a , and not const T& val . Then it will play an important role.

But when trying to describe this f-tion, namely:

 template <typename T> Vector2<T> operator +(Vector2<T> const& l_v, Vector2<T> const& r_v) { ... } 

the most interesting begins, namely the absolutely unpredictable behavior of code analysis "on the fly", from similar code generations when trying to automatically implement the declared function:

 template <typename> Vector2<T> operator+(Vector2 < T > const & l_v, Vector2<T> const& r_v ) { return Vector2<T>(); } // да-да, именно в таком виде, со всеми отступами 

until a categorical refusal to analyze the code, underlining every second word in red.

In general, sometimes (very rarely), CLion perceives everything correctly, but after a while it begins to degrade again.

And now to T const& a . The fact is that if we change the entry in the description of the function to const T& a , then everything will work more than normally. The type of record in the declaration of the function does not affect in any way.


Of course, you could just go to the record of the form const T& a , and the code is compiled, and this is only visual help from this IDE, but I would not write this question if I did not want to solve this problem, so I would like understand how to do this.


PS
CLion version 2018.1, but also tested on 2018.1.6, on a different device, where the result was the same.

    2 answers 2

    Since both the left operand and the right have a class type in the function, it is meaningless to announce such a function as a friend.

    Secondly, if the operation of the function is in no way connected with the state of the object, and the result of the function is a completely different object, then it is generally better to rid the interface of the class from this function and define it separately (but in one module). For example:

     class Integer { int k; public: Integer(int n = 0) : k(n){} //модификаторы //т.е. мы изменяем состояние обьекта *this Integer& operator +=(const Integer& r_v) { k += r_v.k; return *this; } //... //селекторы int get_data() const { return k; } // функция выдает состояние обьекта }; // operator+ (и подобные методы) определяем вне класса inline Integer operator +(const Integer& l_v, const Integer& r_v) { Integer t(l_v); t += r_v; return t; } 

    Such an approach saves the class from the superfluous interface and is the most logical. And if this approach is applied in the writing of your class, then everything becomes much easier ...

     template <typename T> class Vector2 { //... public: Vector2& operator +=(Vector2 const& r_v); }; template <typename T> inline Vector2<T> operator +(Vector2<T> const& l_v, Vector2<T> const& r_v) {...} 

      Friendly you declared some strange function

       template <typename> friend Vector2<T> operator +(Vector2<T> const& l_v, Vector2<T> const& r_v); 

      This function has an unnamed template parameter that is not used anywhere in the function signature. Those. you announced

       template <typename U> friend Vector2<T> operator +(Vector2<T> const& l_v, Vector2<T> const& r_v); 

      (I just gave the name U your nameless parameter).

      In this case, for example, for the class Vector2<int> friend will be

       template <typename U> friend Vector2<int> operator +(Vector2<int> const& l_v, Vector2<int> const& r_v); 

      Why you entered this unnecessary parameter is not clear.

      To the function you defined below

       template <typename T> Vector2<T> operator +(Vector2<T> const& l_v, Vector2<T> const& r_v) { ... } 

      Your ad has nothing to do. Here you have a template parameter that directly affects the function signature. This definition is not a friend of your class. This hash is probably confusing the code analyzer.

      And now to T const& a . The fact is that if we change the entry in the description of the function to const T& a , then everything will work more than normally.

      Not. Nothing will work normally. As I said above, your function is not a friend of the class, with all the ensuing consequences.


      On how to correctly declare patterned friends, it has been written more than once
      Overloading of template statements with division into description and implementation
      Access to private via friend
      Link to unresolved external element

      You, apparently, tried to implement

       template <typename T> class Vector2 { ... template <typename U> // объявляем дружественную ф-цию шаблонной friend Vector2<U> operator +(Vector2<U> const& l_v, Vector2<U> const& r_v); ... }; 

      But why you decided that this option can be "reduced" to yours - it is not clear.

      You can also do without any additional template of your operator, but you will have to define it directly in the class.

       template <typename T> class Vector2 { ... friend Vector2<T> operator +(Vector2<T> const& l_v, Vector2<T> const& r_v) { // Определение придется писать прямо сюда } ... }; 

      for C ++ does not provide syntax for defining such an operator outside the class.

      • But the fact is that everything worked with the nameless arguments of the template, you can check. And the problem with code analysis appeared only when I decided to replace const T& with T const& . - Prunkles
      • And the friendly function needs to be explicitly declared as a template, but using the names T and U separately will mean that all Vector2<T> will be friends with Vector2<U> , which I don’t really need. - Prunkles
      • @Prunkles: What exactly is your "work" I do not know. See a simplified example built according to your scheme: coliru.stacked-crooked.com/a/1a97104432a84487 . As you can see, nothing "works." - AnT
      • @Prunkles: There is nothing wrong with such an "excessive" friendship. But if you want to make a not "lazy" announcement - then look at the links. It shows how this is done. This will have to add a few preliminary announcements. - AnT
      • 2
        @Prunkles: Of course, it is private! This is how we can check if the friend ad worked correctly. In your version, the friend-ad is meaningless - it does nothing and nobody needs it. Your separate function is called that has nothing to do with a friend ad. Why did you even make this friend-announcement? Why do you need "friendship" in general, if everything is publicly available? Throw him out and forget about this problem: coliru.stacked-crooked.com/a/e4af42b7f7b40840 - AnT