【问题标题】:C++ class template undefined reference to function [duplicate]C ++类模板未定义对函数的引用[重复]
【发布时间】:2014-04-30 23:03:04
【问题描述】:

当我从我的主函数中的模板类“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

提前感谢您的帮助!

【问题讨论】:

    标签: c++ c class undefined-reference template-classes


    【解决方案1】:

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

    main.cpp

    #include "myclass.hpp"
    
    int main()
    {
      // ...
    }
    

    myclass.hpp

    #ifndef MYCLASS
    #define MYCLASS
    
    template<class T>
    class MyClass
    {
      T val;
    public:
      MyClass(T val_);
    }
    
    #define MYCLASS_FUNCTIONS
    #include "myclass.cpp"
    
    #endif
    

    myclass.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. 将所有常规函数传递给编译器

    【讨论】:

    • 最佳描述的解决方案。我正好在找这个,一个月后找到了。 (“迟到总比没有好”)。
    【解决方案2】:

    你的班级命名错误。你的类被命名为cai,你所有的函数都属于一个名为number的类:http://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;
    }
    

    【讨论】:

    • 我编辑错了。对此感到抱歉。
    • 我编辑了答案。将您的模板实现放在标题 (.h) 中。非模板实现进入正文 (.cpp)
    • 有人说要修改“number c(3,5);”在主函数中使用“number c = number(3, 5);”但我不断收到前面提到的错误
    • 在这种特定情况下没有区别。您需要做的就是将所有template 函数移动到标头,将所有非模板函数移动到实现文件。
    • 现在可以使用了!非常感谢您的帮助
    【解决方案3】:

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

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

    当您编译@​​987654327@ 时,编译器可以访问模板的定义,但它看不到任何需要特定实例的代码(例如number&lt;int&gt;),因此它不会生成实例。

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

    结果是函数模板没有在 either 对象文件中被实例化——一方面是因为编译器不知道它应该这样做,另一方面是因为它不能——所以当链接器去寻找它们(以解决那些外部引用)时,它找不到它们。这就是您收到错误的原因。

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

    【讨论】:

    • 非常有用。感谢您的帮助!
    猜你喜欢
    • 2012-05-24
    • 2015-10-12
    • 2013-02-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-03
    相关资源
    最近更新 更多