使用模板重载+运算符

5 c++ templates operator-overloading operators visual-studio-2008

嘿,我收到链接器错误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_
Run Code Online (Sandbox Code Playgroud)

请注意,我也有[]重载,所以我只是用它来访问部分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.
}
Run Code Online (Sandbox Code Playgroud)

错误信息:

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
Run Code Online (Sandbox Code Playgroud)

更新:

以下内容现在直接位于类定义之上.我继续得到相同的链接器错误,如上所述.

    template<typename T> 
    class vec;

    template<typename T> 
    vec<T> operator + (const vec<T>&, const vec<T>&); 
Run Code Online (Sandbox Code Playgroud)

更新2:解决方案.

以上更新不正确.sbi的解决方案确实有效,我只是按照以下方式对运营商进行了模板化.

    template<typename T> 
    vec<T> operator +<T> (const vec<T>&, const vec<T>&); 
Run Code Online (Sandbox Code Playgroud)

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.
Run Code Online (Sandbox Code Playgroud)

此外,对于其他读这篇文章的人来说,在他的答案底部查看sbi的笔记是值得的.我一直在做的一些事情是多余的.

感谢大家的帮助.快乐的编码.

Gar*_*ary 6

这里的返回类型:

inline friend vec<T> operator + (const vec<T>&, const vec<T>&);
Run Code Online (Sandbox Code Playgroud)

在这里不匹配:

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

        return product;
    } // Addition.
Run Code Online (Sandbox Code Playgroud)


sbi*_*sbi 6

为了成为模板的朋友,我认为您需要在要与之建立联系的类定义之前声明该模板.但是,要编译此声明,您需要转发声明类模板.所以这应该工作:

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>&);
// ...
Run Code Online (Sandbox Code Playgroud)

这是operator+()功能模板的特定实例,即operator+<T>.(您还可以与模板的所有实例建立联系:

// no forward declarations necessary

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

然而,这比另一个更不常用.)

编辑:大卫注释让我思考(应该已经从一开始就做到了这一点!),而且导致这一发现friend声明是不必要的.你operator+只使用()的一个public成员函数,因此不需要是类的一个.所以上面会简化到vecoperator+=friend

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

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

这里还有一些注意事项:

  • operator+()(你很好地在operator+=()BTW 之上实现)应该每个副本采用左参数.
  • 不要将函数声明inline,因此定义它们.
  • operator+=()返回非const引用,因为每个人都希望f(m1+=m2)即使工作f()需要它的参数作为非const参考.
  • 在类模板内部,在大多数地方,您可以在引用类时省略模板参数列表.所以你可以说vec& operator += (const vec&);.(但是,您不能在模板外部执行此操作 - 例如,在类之外定义该运算符时.)
  • A std::vector的索引类型拼写std::vector<blah>::size_type,而不是 拼写unsigned short.

  • 另外,请注意,您可以在类定义中定义`operator +`(`friend vect operator +(vect lhs,vect const&rhs){return lhs + = rhs;}`),这样做的好处是只有在查找时才能找到`lhs`或`rhs`的类型为'vect <T>`加上你不需要执行双前向声明. (2认同)
  • @Xoorath:差异不在朋友或朋友之间,而是在会员之间或不在会员之间.每个非`静态`成员函数都有一个隐含的`this`参数.对于运营商而言,这将成为运营商的第一个操作数.这就是为什么运算符重载的成员只需要一个参数,而不是作为自由函数重载的运算符.现在,'朋友'只是说"这家伙可能会触摸我的私处".使用`friend`声明,非成员`operator +()`将可以访问类'privates'.没有它,它就不会.由于它不需要访问权限,因此不需要`friend`声明. (2认同)