views:

127

answers:

2

Hey, I'm getting a linker error LNK2019: unresolved external symbol when trying to use an overloaded + operator. I'll show you snip-its from the class, and how I'm using it in main. If you need to see more, let me know, I'm just going to try and keep things concise.

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

Note that I've got [] overloaded as well, so I'm just accessing parts of m_index with it. getIndex() just returns m_index. And size() returns 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 Message:

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

Update:

The following is now directly above the class definition. I continue to get the same linker error, as described above.

    template<typename T> 
    class vec;

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

Update 2: Solution.

The above update is incorrect. sbi's solution did work, I just failed to template the operator as follows.

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

sbi, and david were discussing why I was using friends in the first place. Initially I was using them, because you can not pass two parameters to an overloaded binary operator such as +, and immediate sought after friends as the solution. As it turns out, you can still use the binary operator quite easily with a single parameter. Here is the final solution.

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

Also, for anyone else reading this, its worth while to check out sbi's notes at the bottom of his answer. There are some things I've been doing that are superfluous.

Thanks for the help everyone. Happy coding.

+7  A: 

The return type here:

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

Does not match here:

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

        return product;
    } // Addition.
Gary
Also, it's not the function __declarations__ which need to be marked as `inline`, but the function __definitions__. So it's `friend vec<T> operator + (const vec<T>` and `const vec<T>
sbi
One more thing (really, I should have made my own answer...): Since the operators left operand will be copied right away, that argument should be passed by copy instead of a `const` reference. This used to be seen differently (copying is an implementation detail and shouldn't leak into the interface), but smart people found out that making the copy upon passing the argument gives compilers a few more optimization opportunities (such as omitting the copying when the operand is a temporary that's going to be destroyed anyway).
sbi
Thank you very much sir.
Xoorath
@Xoorath: What @sbi refers to can be read [here](http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/). Conclusion: If you're going to make a copy, do it in the argument.
GMan
Unfortunately that actually did not fix my issue. I still get a 2019 with the following: /** friend vec<T> operator + (vec<T>, vec<T>); **/ and /** template<typename T> vec<T> operator + (vec<T> a, vec<T> b){CODE} **/
Xoorath
@Xoorath: Ah, I see. That's because `friend vec<T> operator + (vec<T>, vec<T>);` befriends a non-template function, while your implementation is a function template.
sbi
I think I understand, but would you know how to get around this issue? Feel free to post a separate answer if you want. Just to get us talking outside of this comment.
Xoorath
@Xoorath: The solution is too long for a comment, so I'll have to add an answer for that. That will take a few minutes.
sbi
@GMan: Actually I first meant to provide a link to that article, but then thought at his current level it might be way over Xoorath's head and omitted it.
sbi
+5  A: 
sbi
Thanks for the reply, and sample. Unfortunately this did not work. I'll keep trying a few things. If you think of anything, I'll be checking back regularly.
Xoorath
@Xoorath: "It doesn't work" is too vague to be able to say anything. (I actually have a version here that compiles and links with VC, so I know it does work in principle.)
sbi
Sorry buddy. One sec. I'll update my code snippet.
Xoorath
@Xoorath: Don't change the original code, as this would render old answers invalid. Paste the new code at the bottom of your answer instead.
sbi
@sbi: Alright. I'll go do that now. Sorry, I didn't read that post before the edit. I'm still new here, so thanks for your patience.
Xoorath
Got it! Thank you.I didn't see that you were declaring the template type after the operator in the definition. "operator +<T>".Thank you very much sbi, you've been a great help.
Xoorath
@Xoorath: Yes, as I've added later to the answer, this curious `operator+<T>` syntax names a _specific instance_ of the `operator+` function template. (And my answer built on top of Gary's, just adding a few things here and there.)
sbi
Oh, and the code in your answer still applies `inline` to function __declarations__.
sbi
Yes, because that didn't aid the solution of my problem I didn't change it here. However I've already started to take out the superfluous code. Again, thank you very much.
Xoorath
Also, note that you can define `operator+` inside the class definition (`friend vect operator+( vect lhs, vect const }`) and this has the advantage of only being found in lookups when either the `lhs` or `rhs` are of type `vect<T>` plus you don't need to perform the double forward declarations.
David Rodríguez - dribeas
@David: Yeah, pretty good idea. I Don't know why I didn't think of that...
sbi
@David: Hah, once you start thinking... __Why would that operator be a friend at all?__ There is no need to, as it only uses public member function of `vec`! I changed my answer accordingly.
sbi
Some authors --I don't remember which, I would have to look it up among different books-- suggest using the friend declaration in this case --even if unneeded-- because it limits visibility of the templated `operator+` to only those cases where one of the operands is actually a `vect<T>`. That is, (ab)using the `friend` keyword to (kind of) reduce the scope of the free function.
David Rodríguez - dribeas
@David: I'm not sure how this would be more limiting than an `operator+()` taking two instances of `vect<T>`. This operator can only be used with `vec` instances anyway.
sbi
@sbi: Hey, thanks a lot for the update. However there is an issue with the sample above, that is easy to fix. When overloading a binary operator such as +, you can't have two parameters. Thats one of the reasons I used friends. **However** I did a bit of reading on the associated error message, http://msdn.microsoft.com/en-us/library/1zy85x1e.aspx It turned out to be pretty simple to fix. Just make one param, and make a temp var = *this. I'll update with the fix shortly.
Xoorath
@Xoorath: The difference isn't between friend or not friend, it's between member or not member. Every non-`static` member function has an implicit `this` argument. For operators, this will become the operator's first operand. That's why operators overloaded as members take one argument less than operators overloaded as free functions. Now, `friend` just says "this guy might touch my private parts". With the `friend` declaration, a non-member `operator+()` will have access to the class' privates. Without it, it won't. Since it doesn't need that access, it doesn't need the `friend` declaration.
sbi
Interesting. Thank you once more for the insight.
Xoorath