5

Oye, recibo un error de enlazador LNK2019: símbolo externo no resuelto al intentar usar un operador + sobrecargado. Te mostraré snip-its de la clase, y cómo lo estoy usando en main. Si necesita ver más, hágamelo saber, voy a tratar de mantener las cosas concisas.Sobrecarga + Operador con plantillas

/** 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_ 

Tenga en cuenta que tengo [] sobrecargado, así, así que sólo voy a acceder a partes de m_index con él. getIndex() simplemente devuelve m_index. Y el tamaño() devuelve 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. 
} 

mensaje de error:

Error 1 error LNK2019: unresolved external symbol "class xoor::vec<double> __cdecl xoor::operator+(class xoor::vec<double> const &,class xoor::vec<double> const &)" ([email protected]@YA?A[email protected]@[email protected]@[email protected]) referenced in function "void __cdecl testHook(void)" ([email protected]@YAXXZ) main.obj 

Actualización:

El siguiente es ahora directamente por encima de la definición de clase. Continúo obteniendo el mismo error de enlazador, como se describe arriba.

template<typename T> 
    class vec; 

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

Actualización 2: Solución.

La actualización anterior es incorrecta. La solución de sbi sí funcionó. No reproduje el operador de la siguiente manera.

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

sbi y David estaban discutiendo por qué estaba usando amigos en primer lugar. Inicialmente los estaba usando, porque no se pueden pasar dos parámetros a un operador binario sobrecargado, como +, y amigos buscados inmediatamente como la solución. Como resultado, todavía puede usar el operador binario con bastante facilidad con un solo parámetro. Aquí está la solución final.

// ... 
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. 

Además, para cualquier otra persona leyendo esto, vale la pena, mientras que para ver las notas de OSE en el fondo de su respuesta. Hay algunas cosas que he estado haciendo que son superfluas.

Gracias por la ayuda de todos. Feliz codificación.

+0

Si esta es la tarea (y parece sospechosamente), debe agregar la etiqueta 'homework'. Muchos de nosotros respondemos las preguntas de la tarea de manera diferente, de modo que aprendas tanto como sea posible de esto (mientras que otras preguntas generalmente se hacen para que quien pregunta puede seguir haciendo lo que hace lo más rápido posible). – sbi

Respuesta

7

Con el fin de hacer amistad con una plantilla, creo que tendrá que declarar que la plantilla antes definición de clase en la que desea hacerse amigo de ella. Sin embargo, para compilar esta declaración, deberá reenviar-declarar la plantilla de clase. Así que esto debería funcionar:

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>&); 
// ... 

Esto se hace amigo de una instancia específica de la plantilla operator+() función, a saber operator+<T>. (También puede hacerse amigo de todas las instancias de una plantilla:

// no forward declarations necessary 

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

Sin embargo, eso es menos útil a menudo que el otro.)

Editar: Un comentario de David me hizo pensar (debería haber hecho esto desde el principio) y que conducen al descubrimiento de que la declaración friend es innecesaria!. Su operator+ solo está utilizando una función de miembro public de vec (operator+=) y, por lo tanto, no necesita ser un friend de la clase. Así lo anterior simplificaría a

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

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

Aquí hay unas cuantas notas:

  • operator+() (que muy bien implementado en la parte superior de operator+=(), por cierto) deben tomar su argumento izquierda por copia.
  • No declaran funciona como inline, definen ellos así.
  • operator+=() Tener un retorno no const referencia, porque todo el mundo espera f(m1+=m2) para trabajar incluso si f() toma su argumento como una referencia no const.
  • Dentro de una plantilla de clase, en la mayoría de los lugares puede omitir la lista de parámetros de plantilla cuando se hace referencia a la clase. Entonces puedes decir vec& operator += (const vec&);. (No se puede hacer esto fuera de la plantilla, aunque - por ejemplo, en la definición de ese operador fuera de la clase.)
  • Un tipo de índice std::vector 's se escribe std::vector<blah>::size_type, nounsigned short.
+0

Gracias por la respuesta y la muestra. Desafortunadamente esto no funcionó. Seguiré probando algunas cosas. Si piensas en algo, estaré revisando regularmente. – Xoorath

+0

@Xoorath: "No funciona" es demasiado vago para poder decir algo. (De hecho, tengo una versión aquí que compila y enlaza con VC, así que sé que funciona en principio). – sbi

+0

Lo siento amigo. Un segundo. Actualizaré mi fragmento de código. – Xoorath

7

El tipo de retorno aquí:

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

no coincide aquí:

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

     return product; 
    } // Addition. 
+0

Además, no es la función __declaraciones__ la que debe marcarse como 'en línea', sino la función __definiciones__. Por lo que es 'amigo vec operador + (const vec y, const vec y);' y 'const vec y operador + = (const vec y);', pero 'línea vec operador + (const vec &, const vec &) {...} 'y' const vec en línea & operator + = (const vec &) {...} '. Ah, y ¿cuál es la razón para tener '+ =' return a 'const vec &'? Creo que esto debería ser una referencia no incluida – sbi

+1

Una cosa más (en realidad, debería haber hecho mi propia respuesta ...): dado que los operadores dejaron el operando se copiará de inmediato, ese argumento debería pasar por copia en lugar de una referencia 'const'. Esto solía verse de manera diferente (la copia es un detalle de implementación y no debe filtrarse a la interfaz), pero las personas inteligentes descubrieron que hacer la copia al pasar el argumento brinda a los compiladores algunas oportunidades de optimización adicionales (como omitir la copia cuando el operand es un temporal que se va a destruir de todos modos). – sbi

+0

Muchas gracias señor. – Xoorath