Перегрузка + оператор с шаблонами - PullRequest
5 голосов
/ 26 июля 2010

Привет, я получаю ошибку компоновщика LNK2019: неразрешенный внешний символ при попытке использовать перегруженный оператор +. Я покажу вам отрывок из класса и то, как я использую его в основном. Если вам нужно увидеть больше, дайте мне знать, я просто постараюсь сделать вещи краткими.

/** vec.h **/
#ifndef __VEC_H_
#define __VEC_H_

#include <iostream>
#include <vector>

namespace xoor{

    template<typename T> 
    class vec{

    public:
        inline friend vec<T> operator + (const vec<T>&, const vec<T>&);
        inline const vec<T>& operator += (const vec<T>&);

    private:
        std::vector<T> m_index;
    }; // Vec.


    template<typename T> 
    vec<T>& operator + (const vec<T>& a, const vec<T>& b){
        vec<T> product = a;
        product += b;

        return product;
    } // Addition.

    template<typename T> 
    const vec<T>& vec<T>::operator += (const vec<T>& v){
        for (unsigned short i =0; i < m_index.size(); ++i){
            if (i >= v.size())
                break;
            m_index[i] += v.getIndex()[i];
        }

        return * this;
    } // Addition Compound.


} // xoor

#endif // __VEC_H_

Обратите внимание, что у меня [] также перегружены, так что я просто получаю доступ к частям m_index с ним. getIndex () просто возвращает m_index. И size () возвращает m_index.size ()

/** main.cpp **/

#include <iostream>
#include "vec.h"

void testHook();

int main(){
    testHook();
    system("PAUSE");
    return 0;
}

void testHook(){
    using namespace xoor;
    vec<double> vA(3); // passing 3 for 3 elements
    vec<double> vB(3);

    // v + v
    std::cout << "\n\tA + B = ";
    vec<double> vAB(3);
    vAB = vA + vB; // PRODUCES THE LNK2019
    vAB.print(std::cout); // Outputs the vec class to the console.
}

Сообщение об ошибке:

Error   1   error LNK2019: unresolved external symbol "class xoor::vec<double> __cdecl xoor::operator+(class xoor::vec<double> const &,class xoor::vec<double> const &)" (??Hxoor@@YA?AV?$vec@N@0@ABV10@0@Z) referenced in function "void __cdecl testHook(void)" (?testHook@@YAXXZ)    main.obj

Обновление:

Следующее теперь прямо над определением класса. Я продолжаю получать ту же ошибку компоновщика, как описано выше.

    template<typename T> 
    class vec;

    template<typename T> 
    vec<T> operator + (const vec<T>&, const vec<T>&); 

Обновление 2: решение.

Данное обновление неверно. Решение sbi сработало, я просто не смог шаблонизировать оператор следующим образом.

    template<typename T> 
    vec<T> operator +<T> (const vec<T>&, const vec<T>&); 

sbi, и Дэвид обсуждали, почему я вообще использовал друзей. Первоначально я использовал их, потому что вы не можете передать два параметра перегруженному двоичному оператору, такому как +, и сразу же искать друзей в качестве решения. Как оказалось, вы все еще можете довольно легко использовать бинарный оператор с одним параметром. Вот окончательное решение.

// ...
template<typename T> 
class vec{
    public:
    const vec<T> operator + (const vec<T>&, const vec<T>&)const;
    // ...

}; // Vec.

template<typename T> 
const vec<T> vec<T>::operator + (const vec<T>& v)const{
    matrix<T> product = *this;
    vec(product += v);
} // Addition.

Кроме того, для всех, кто читает это, стоит заглянуть в заметки sbi внизу его ответа. Есть некоторые вещи, которые я делал, которые излишни.

Спасибо за помощь всем. Удачного кодирования.

Ответы [ 2 ]

6 голосов
/ 26 июля 2010

Чтобы подружиться с шаблоном, я думаю, вам нужно объявить этот шаблон перед определением класса, в котором вы хотите подружиться с ним.Однако для того, чтобы это объявление скомпилировалось, вам нужно заранее объявить шаблон класса.Так что это должно работать:

template<typename T> 
class vec;

template<typename T> 
vec<T> operator + (vec<T>, const vec<T>&);

template<typename T> 
class vec{
public:
    friend vec<T> operator +<T> (vec<T>, const vec<T>&);
// ...

Это оказывает поддержку определенному экземпляру шаблона функции operator+(), а именно operator+<T>.(Вы также можете подружиться со всеми экземплярами шаблона:

// no forward declarations necessary

template<typename T>
class some_class {
  template<typename U>
  friend void f(vec<U>&);
  // ... 
};

Однако это менее полезно, чем другой.)

Редактировать: Комментарий Дэвида заставил меня задуматься (должен был сделать это с самого начала!), И это привело к открытию, что объявление friend не нужно .Ваш operator+ использует только одну public функцию-член vec (operator+=) и, следовательно, не должен быть friend класса.Таким образом, вышесказанное упростится до

template<typename T> 
class vec{
public:
    // ...
};

template<typename T> 
vec<T> operator + (vec<T> a, const vec<T>& b){
    a += b;
    return a;
}

Вот еще несколько примечаний:

  • operator+() (которые вы хорошо реализовали поверх operator+=(), кстати)должен взять свой левый аргумент за копию.
  • Не объявлять функции как inline, определять их так.
  • Пусть operator+=() вернет ссылку, отличную от const, потому что все ожидают, что f(m1+=m2) будет работать, даже если f() примет аргумент в качестве ссылки не const.
  • Внутри шаблона класса в большинстве мест вы можете опустить список параметров шаблона при обращении к классу.Так что вы можете сказать vec& operator += (const vec&);.(Однако вы не можете сделать это вне шаблона - например, при определении этого оператора вне класса.)
  • A std::vector тип индекса пишется std::vector<blah>::size_type, не unsigned short.
6 голосов
/ 26 июля 2010

Тип возврата здесь:

inline friend vec<T> operator + (const vec<T>&, const vec<T>&);

Здесь не совпадает:

template<typename T> 
    vec<T>& operator + (const vec<T>& a, const vec<T>& b){
        vec<T> product = a;
        product += b;

        return product;
    } // Addition.
...