【问题标题】:Problems with template in c++ [duplicate]C ++中的模板问题[重复]
【发布时间】:2012-12-26 12:12:18
【问题描述】:

可能重复:
Undefined symbol on a template operator overloading function

这是我的源代码。 在Number.h

#ifndef NUMBER_H
#define NUMBER_H

#include <iostream>
using std::istream;
using std::ostream;

template <class T> class Number;

template <class T>
ostream& operator<<(ostream&, const Number<T>&);

template <class T>
istream& operator>>(istream&, Number<T>&);

template <class T>
class Number{
public:
    Number(const T &n)  :i(n) {}
    Number()            :i(0) {}
    T& operator+(const Number&rhs) const;
    T& operator-(const Number&rhs) const;
    T& operator*(const Number&rhs) const;
    T& operator/(const Number&rhs) const;
    friend ostream& operator<< <T> (ostream& , const Number<T>&);
    friend istream& operator>> <T> (istream& , Number<T>&);
private:
    T i;
};

#endif

Number.cpp

#include "Number.h"

template<class T> 
T& Number<T>::operator+(const Number&rhs) const
{
    return i+rhs.i;
}

template<class T> 
T& Number<T>::operator-(const Number&rhs) const
{
    return i-rhs.i;
}

template<class T> 
T& Number<T>::operator*(const Number&rhs) const
{
    return i*rhs.i;
}

template<class T>
T& Number<T>::operator/(const Number&rhs) const
{
    return i/rhs.i;
}

template<class T>
ostream& operator<<(ostream&os , const Number<T>&rhs)
{
    return os<< rhs.i;
}

template<class T>
istream& operator>>(istream&is , Number<T>&rhs)
{
    return is >> rhs.i;
}

我不知道为什么会有

undefined reference to `std::istream& operator>><double>(std::istream&,Number<double>&)'
undefined reference to `Number<double>::operator+(Number<double> const&) const'

错误等等

【问题讨论】:

标签: c++ templates


【解决方案1】:

使用 .hpp 作为模板,您不能返回对临时对象的引用。

数字.h

#ifndef NUMBER_H
#define NUMBER_H

#include <iostream>
using std::istream;
using std::ostream;

template <class T> class Number;

template <class T>
ostream& operator<<(ostream&, const Number<T>&);

template <class T>
istream& operator>>(istream&, Number<T>&);

template <class T>
class Number{
        public:
                Number(const T &n)  :i(n) {}
                Number()            :i(0) {}
                T operator+(const Number&rhs) const; // Error Here return T not T&
                T operator-(const Number&rhs) const;
                T operator*(const Number&rhs) const;
                T operator/(const Number&rhs) const;
                friend ostream& operator<< <T> (ostream& , const Number<T>&);
                friend istream& operator>> <T> (istream& , Number<T>&);
        private:
                T i;
};

#include <number.hpp>

#endif

数字.hpp

#ifndef NUMBER_HPP
#define NUMBER_HPP

template<class T> 
T
Number<T>::operator+(const Number& rhs) const
{
        return i + rhs.i;
}

template<class T> 
T
Number<T>::operator-(const Number&rhs) const
{
        return i-rhs.i;
}

template<class T> 
T
Number<T>::operator*(const Number&rhs) const
{
        return i*rhs.i;
}

template<class T>
T
Number<T>::operator/(const Number&rhs) const
{
        return i/rhs.i;
}

template<class T>
ostream& operator<<(ostream&os , const Number<T>&rhs)
{
        return os<< rhs.i;
}

template<class T>
istream& operator>>(istream&is , Number<T>&rhs)
{
            return is >> rhs.i;
}

#endif

main.cpp

    #include <iostream>
    #include <number.h>

    int
    main(int, const char**)
    {
        Number<double>  value(1);
        Number<double>  add(3);

        std::cout << value + add << std::endl;
        std::cout << value * add << std::endl;
        std::cout << value - add << std::endl;
        std::cout << value / add << std::endl;
        return 0;
}

【讨论】:

    【解决方案2】:

    所有这些成员函数的定义都需要对任何实例化模板的翻译单元可用。想象一个包含Number.h 并尝试使用Number&lt;int&gt; 的文件。然后,编译器需要为Number 生成所有代码,这些代码用T 实例化为int。如果只看到Number.h,它怎么能做到这一点?它不知道成员函数的定义。

    解决方法是将成员函数的定义(来自Number.cpp 的所有内容)放在Number.h 中。或者,有些人喜欢将Number.cpp 命名为Number.tpp,而不是Number.cpp 中的#include "Number.h",而是将#include "Number.tpp" 放在Number.h底部 - 基本上是颠倒包含所以标头始终包含实现。

    【讨论】:

    • 非常感谢。我是template的新手
    • 你能解释一下为什么#include "Number.h"在有template的情况下更常见
    • @user1668903 恐怕我不太明白这个问题。每当您实例化一个模板时,例如Number&lt;int&gt;,编译器需要能够生成类Number,并将所有出现的T 替换为int。为此,它需要能够看到Number 的所有代码,因此头文件必须同时包含头文件和实现。
    • 对不起,我的意思是为什么人们不会总是在Number.h 中使用#include "Number.cpp" 而不是在Number.cpp 中使用#include "Number.h"
    • @user1668903 因为一个正常的实现文件(当它不是模板实现时)需要单独编译。例如,如果您有一个未模板化的类T,并且有两个文件T.hT.cpp,您将在某个时候编译T.cpp,其中必须包含来自T.h 的类的定义.如果T.cpp 不包含T.h,它将无法编译,因为没有类定义。但是使用您的模板实现Number.cpp,它不需要单独编译。事实上,它需要包含在每个使用它的翻译单元中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-05
    • 1970-01-01
    • 1970-01-01
    • 2015-08-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多