8

当我从我的主函数中的模板类“add”和“greater”调用这两个函数时,我不断得到未定义的引用。

所以,我有:number.h

#ifndef NUMBER_H
#define NUMBER_H

template <class T>
class number {
public:
    T x;
    T y;

    number (int a, int b){
        x=a; y=b;}
    int add (T&);
    T greater ();
};

#endif

数字.cpp

#include "number.h"

template <class T>
int number<T>::add (T& rezAdd){
    rezAdd = x+y;
    return 1;
}

template <class T>
T number<T>::greater (){
        return x>y? x : y;
}

我的主要文件是:resolver.cpp

#include <stdio.h>
#include <stdlib.h>
#include "number.h"

int main (int argc, char **argv) {
    int aux;
    number<int> c(3,5);

    c.add(aux);
    printf ("number added [%d]\n", c.add(aux));
    printf ("greater number: [%d]\n", c.greater());

    return 0;
}

我不断收到的错误是:

g++ -Wall -o tema1 resolver.cpp number.cpp
/tmp/ccX483J4.o: In function `main':
resolver.cpp:(.text+0x34): undefined reference to `number<int>::add(int&)'
resolver.cpp:(.text+0x47): undefined reference to `number<int>::add(int&)'
resolver.cpp:(.text+0x64): undefined reference to `number<int>::greater()'
collect2: ld returned 1 exit status
make: *** [all] Error 1

我在这里先向您的帮助表示感谢!

4

3 回答 3

6

我更喜欢将我的所有函数都放在.cpp文件中,无论它们是模板函数还是常规函数。有一种方法可以通过一些基本的#ifndef魔法来做到这一点。以下是您可以执行的操作:

主文件

#include "myclass.hpp"

int main()
{
  // ...
}

我的类.hpp

#ifndef MYCLASS
#define MYCLASS

template<class T>
class MyClass
{
  T val;
public:
  MyClass(T val_);
}

#define MYCLASS_FUNCTIONS
#include "myclass.cpp"

#endif

我的类.cpp

#ifndef MYCLASS_FUNCTIONS
#include "myclass.hpp"

// regular functions:
// ...

#else

// template functions:
template<class T>
MyClass<T>::MyClass(T val_)
    :val(val_)
{}

// ...
#endif

这是预编译器的看法。我们有两个.cpp文件。

  1. 当我们编译 main.cpp 时,我们:
    1. 包括myclass.hpp
    2. 检查MYCLASS未定义,它是
    3. 定义它
    4. 给编译器生成类的定义(来自模板类)
    5. 包括myclass.cpp
    6. 定义MYCLASS_FUNCTIONS
    7. 检查是否MYCLASS_FUNCTIONS已定义,它是
    8. 给编译器生成函数的定义(来自模板函数)
  2. 当我们编译 myclass.cpp
    1. 检查是否MYCLASS_FUNCTIONS已定义,它不是
    2. 包括myclass.hpp
    3. 检查MYCLASS未定义,它是
    4. 定义它
    5. 给编译器类的定义
    6. 包括myclass.cpp
    7. myclass.hpp再次包含
    8. 这个时间MYCLASS是定义的所以里面什么都不做,返回myclass.cpp
    9. 检查是否MYCLASS_FUNCTIONS已定义,它是
    10. 给编译器生成函数的定义(来自模板函数)
    11. 退出包括两次
    12. 将所有常规函数传递给编译器
于 2014-11-08T12:12:28.743 回答
5

您的班级名称错误。你的类被命名为你cai所有的函数都属于一个名为的类:http number: //ideone.com/ZayX0c

还有一件事.. .cpp 文件中不能有模板。模板函数/定义与类声明一起放在标题中。这是未定义函数错误的原因。非模板函数放在 .cpp 中。

#include <cstdio>
#include <cstdlib>

template <class T>
class number {
public:
    T x;
    T y;

    number (int a, int b){
        x=a; y=b;}
    int add (T&);
    T greater ();
};

template <class T>
int number<T>::add (T& rezAdd){
    rezAdd = x+y;
    return 1;
}

template <class T>
T number<T>::greater (){
        return x>y? x : y;
}


int main (int argc, char **argv) {
    int aux;
    number<int> c(3,5);

    c.add(aux);
    printf ("number added [%d]\n", c.add(aux));
    printf ("greater number: [%d]\n", c.greater());

    return 0;
}
于 2014-03-23T18:25:57.423 回答
4

addgreater函数模板的定义移动到您的number.h.

请记住,add它们greater不是函数,它们是函数模板。要创建实际函数,编译器必须为特定类型实例化模板,例如int,并且只有在它发现需要实例时才能访问模板的定义时才能这样做。

当您 compilenumber.cpp时,编译器可以访问模板的定义,但它看不到任何需要特定实例的代码(例如number<int>),因此它不会生成实例。

当您 compileresolver.cpp时,编译器会看到它需要为该int类型实例化这些模板,但它不能,因为它没有它们的定义。所以它生成“外部引用”,基本上是告诉链接器在其他目标文件中查找这些函数的注释。

结果是函数模板没有在任何一个目标文件中被实例化——一个是因为编译器不知道它应该实例化,另一个是因为它不能——所以当链接器去寻找它们时(到解决那些外部引用),它找不到它们。这就是你得到错误的原因。

将模板函数定义移动到头文件中,使它们在编译器编译时对编译器可见main.cpp,因此它能够为该int类型实例化这些函数。.cpp正是出于这个原因,函数模板通常需要在头文件而不是文件中定义。

于 2014-03-23T18:35:21.620 回答