4

Хочу перегрузить оператор - через дружественную функцию. В файле класса

namespace mth
{
    template <typename T>
    class Vector
    {
     //something
     public:
     friend Vector& operator - (const Vector<T>& v1, const Vector<T>& v2);
    };

template<typename T> Vector<T>& operator-(const Vector<T>& v1, const Vector<T>& v2) { assert(v1.length != v2.length && "The array lengths must be equal");

Vector&lt;T&gt;temp(v1.length);
for (int i = 0; i &lt; v1.length; i++)
    temp.buffer[i] = v1.buffer[i] + v2.buffer[i];

return temp;

} }

В main подразумевается какое-то такое использование

mth::Vector<int> example(2);
    mth::Vector<int> example2(2);
example[0]=1;
example[1]=2;

example2[0]=5;
example2[1]=8;

mth::Vector&lt;int&gt; example3(example - example2);

Если не использовать минус в main, то все компилится, а если использовать, то пишет

LNK2019 ссылка на неразрешенный внешний символ "class mth::Vector<int> & __cdecl mth::operator-(class mth::Vector<int> const &,class mth::Vector<int> const &)" (??Gmth@@YAAAV?$Vector@H@0@ABV10@0@Z) в функции _main.

Минимальный компилящийся пример: main

#include "comandSource.h"

int main() { mth::Vector<int> example(2); mth::Vector<int> example2(2);

example[0]=1;
example[1]=2;

example2[0]=5;
example2[1]=8;

mth::Vector&lt;int&gt; example3(example + example2);
example3.print();

return 0;

}

comandSource.h

#pragma once

#include <iostream> #include <math.h> #include <assert.h>

using namespace std;

namespace mth {

template &lt;typename T&gt;
class Vector
{
private:
    unsigned int length = 0;
    T* buffer = NULL;

public:
    Vector();
    Vector(const Vector&amp; r);
    Vector(int _length);

    ~Vector() { delete[] buffer; }

    void print();

    Vector operator + (const Vector&amp; other);    
    T&amp; operator [] (const int index);
    friend Vector&amp; operator - (const Vector&lt;T&gt;&amp; v1, const Vector&lt;T&gt;&amp; v2);
};

template &lt;class T&gt; Vector&lt;T&gt;::Vector()
{

    length = 1;
    for (int i = 0; i &lt; length; i++)
        buffer[i] = 0;
}

template &lt;class T&gt; Vector&lt;T&gt;::Vector(int _length)
{
    length = _length;
    buffer = new T[length];
    for (int i = 0; i &lt; length; i++)
        buffer[i] = 0;
}

template &lt;class T&gt; Vector&lt;T&gt;::Vector(const Vector &amp; arg)
{

    length = arg.length;
    buffer = new T[length];
    for (int i = 0; i &lt; length; i++)
        buffer[i] = arg.buffer[i];
}

template&lt;class T&gt; void Vector&lt;T&gt;::print()
{
    cout &lt;&lt; &quot;{ &quot;;
    for (int i = 0; i &lt; length; i++)
        cout &lt;&lt; &quot;'&quot; &lt;&lt; buffer[i] &lt;&lt; &quot;' &quot;;
    cout &lt;&lt; &quot;}&quot;;
}


template &lt;class T&gt;
Vector&lt;T&gt; Vector&lt;T&gt;::operator+(const Vector&amp; arg)
{

    if (length != arg.length)
    {
        cout &lt;&lt;&quot;[ERROR] vectors doesn't match by size&quot;&lt;&lt;endl;
        exit(1);
    }

    Vector&lt;T&gt;temp(length);
    for (int i = 0; i &lt; length; i++)        
        temp.buffer[i] = buffer[i] + arg.buffer[i];

    return temp;
}

template&lt;typename T&gt;
T&amp; Vector&lt;T&gt;::operator[](const int index)
{
    assert(index &gt; -1 &amp;&amp; index &lt; length &amp;&amp; &quot;Invalid array index&quot;);
    return buffer[index];
}

template&lt;typename T&gt;
Vector&lt;T&gt;&amp; operator-(const Vector&lt;T&gt;&amp; v1, const Vector&lt;T&gt;&amp; v2)
{
    assert(v1.length != v2.length &amp;&amp; &quot;The array lengths must be equal&quot;);

    Vector&lt;T&gt;temp(v1.length);
    for (int i = 0; i &lt; v1.length; i++)
        temp.buffer[i] = v1.buffer[i] + v2.buffer[i];

    return temp;
}

}

  • насколько я понимаю - проблема в namespace - нужно вынести функцию из mth – Andrej Levkovitch Oct 23 '20 at 15:49
  • Перегруженный через метод класса оператор + отлично работает из mth – Alrond2198 Oct 23 '20 at 15:51
  • А почему вы возвращаете из оператора ссылку на переменную, находящуюся в стеке? – maestro Oct 23 '20 at 15:55
  • Хороший вопрос, на самом деле. Я так понял, не надо так делать? – Alrond2198 Oct 23 '20 at 15:57
  • приведите минимальный компилируемый пример – Andrej Levkovitch Oct 23 '20 at 15:57
  • После выхода из функции вектор temp удаляется из стека, следовательно, ссылка становится недействительной. Но к вопросу это прямого отношения не имеет. – maestro Oct 23 '20 at 16:02

1 Answers1

3

Выносите шаблон наружу, а дружественную функцию определяете как operator-<>

namespace mth
{
    template<typename T> class Vector;
    template<typename T>
    Vector<T> operator-(const Vector<T>& v1, const Vector<T>& v2);
template &lt;typename T&gt;
class Vector
{
  // ...
  friend Vector&lt;T&gt; operator-&lt;&gt;(const Vector&lt;T&gt;&amp; v1, const Vector&lt;T&gt;&amp; v2);
}
//...

template<typename T> Vector<T> operator-(const Vector<T>& v1, const Vector<T>& v2) {/.../} }

Убрал пока ссылку с возвращаемого типа, эту проблему решите отдельно.

cpp.sh


Второй вариант, о котором сразу почему-то не подумал(напомнил @Harry) — объявить шаблонную дружественную функцию по месту:

template <class Y>
friend Vector<Y> operator-(const Vector<Y>& v1, const Vector<Y>& v2);

cpp.sh

vp_arth
  • 27,179
  • Выглядит странно, но оно работает. Спасибо, и не могли бы вы пояснить, почему вынесены вверх эти два объявления? – Alrond2198 Oct 23 '20 at 16:40
  • И у нас получаются два объявления и одно определение для оператора? Первый раз такое вижу – Alrond2198 Oct 23 '20 at 16:42
  • friend - это только декларация дружественности к шаблонной функции, которую мы объявляем ранее. – vp_arth Oct 23 '20 at 16:43
  • Вообще, лучше ну её эту дружбу, тем более в шаблонах) С плюсом вот у вас никаких проблем)) – vp_arth Oct 23 '20 at 16:51
  • Но мне казалось, что это "не по стилю", типа так делать нехорошо – Alrond2198 Oct 23 '20 at 17:01