未定义参考至(g ++编译与静态库)

问题描述:

项目文件是这样的:未定义参考至(g ++编译与静态库)

source 
    parser 
    parser.cpp 
    parser.hpp 
    brain 
    brain.cpp 
    brain.hpp 

我第一次运行这两个命令(PWD source/brain/):

g++ -c brain.cpp -o brain.o 
ar rvs brain.a brain.o 

我复制既brain.abrain.hppsource/parser/。然后,我跑到这个命令(PWD source/parser):

g++ parser.cpp brain.a -o parser 

而且我得到了这个错误:

/tmp/cceGRLZn.o: In function `main': 
parser.cpp:(.text+0x1cc): undefined reference to `std::brain<long long>::brain()' 
parser.cpp:(.text+0x205): undefined reference to `std::brain<long long>::init(int)' 
parser.cpp:(.text+0x26b): undefined reference to `std::brain<long long>::work()' 
parser.cpp:(.text+0x2a4): undefined reference to `std::brain<long long>::clear()' 
parser.cpp:(.text+0x2ec): undefined reference to `std::brain<long long>::~brain()' 
parser.cpp:(.text+0x322): undefined reference to `std::brain<long long>::~brain()' 
/tmp/cceGRLZn.o: In function `int parser_extract_args<long long>(std::basic_string<char, std::char_traits<char>, std::allocator<char> >&, int, short&, std::brain<long long>&)': 
parser.cpp:(.text._Z19parser_extract_argsIxEiRSsiRsRSt5brainIT_E[int parser_extract_args<long long>(std::basic_string<char, std::char_traits<char>, std::allocator<char> >&, int, short&, std::brain<long long>&)]+0x17b): undefined reference to `std::brain<long long>::push_back(long long)' 
parser.cpp:(.text._Z19parser_extract_argsIxEiRSsiRsRSt5brainIT_E[int parser_extract_args<long long>(std::basic_string<char, std::char_traits<char>, std::allocator<char> >&, int, short&, std::brain<long long>&)]+0x37a): undefined reference to `std::brain<long long>::push_back(long long)' 
collect2: ld returned 1 exit status 

源文件:

brain.cpp [http://ideone.com/GNUxmH][1] 
brain.hpp [http://ideone.com/M2IFAI][2] 
parser.cpp [http://ideone.com/fJRzhD][3] 
parser.hpp [http://ideone.com/mj6dST][4] 

我该怎么办?

+0

看起来您正在通过头文件和源代码使用模板,您需要在头文件中定义这些模板并包含它们。 – 2013-04-06 12:33:59

+0

你能告诉我怎么样,这是我第一次使用模板,或者至少请参考教程。 – 2013-04-06 12:34:48

我敢打赌,你在.cpp文件中实现了你的班级模板brain的成员函数。您需要在头文件中提供模板定义,以便编译器在看到模板实例时可以生成适当的代码。因此请将brain.cpp的内容移至brain.h

作为一个例子,考虑这三个文件:

  • test.h

    template <typename T> 
    struct test 
    { 
        void foo(T); 
    }; 
    
  • test.cpp

    #include "test.h" 
    
    template <typename T> 
    void test<T>::foo(T x) 
    { 
        // do something with x 
    } 
    
  • main.cpp

    #include "test.h" 
    
    int main() 
    { 
        test<int> t; 
        t.foo(5); 
    } 
    

每个.cpp被单独编译,然后连接在一起。想象一下你是编译器,并且你正在编译main.cpp。您会看到该代码想要使用实例化的test模板作为int。所以现在您需要为test<int>::foo生成适当的代码,但要做到这一点,您需要看到该函数的定义。不幸的是,你还没有看到它,所以你不能编译这个程序。

而是,foo定义应该被移动到头部文件,导致这个两个文件程序:

  • test.h

    template <typename T> 
    struct test 
    { 
        void foo(T); 
    }; 
    
    // Alternatively, you can define this up in the class definition 
    void test<T>::foo(T x) 
    { 
        // do something with x 
    } 
    
  • main.cpp

    #include "test.h" 
    
    int main() 
    { 
        test<int> t; 
        t.foo(5); 
    } 
    

请注意,你不应该添加自己的报关行std命名空间:

The behavior of a C++ program is undefined if it adds declarations or definitions to namespace std or to a namespace within namespace std unless otherwise specified.

第一件事:任何实体不添加到std命名空间。这给你的程序未定义的行为

从您的消息看来,您似乎已将名为brain的类添加到std命名空间。从std名称空间中删除brain,并将其放入您的某个名称空间。您可以添加到std名称空间的唯一一件事是属于std名称空间的模板的专业

其次,除非你提供你正在使用整个程序,你应该把类模板的成员函数的定义,包含它们的声明相同的头文件中的类模板明确的实例,使确保它们从实例化点可见。

将它们分别放在一个单独的.cpp文件中使得编译器无法为您从包含其定义的其他翻译单元调用的成员函数生成代码。 This Q&A on *也可能帮助你。

需要声明与您需要的类型的大脑模板类的一个实例,所以在brain.cpp,在文件的结尾,你应该把:

template class brain <long long> ; 

当你编译大脑。 cpp,除非在那里有模板说明符,否则不会创建任何可链接的代码,因为它不能在没有类型声明的情况下实例化模板类。也就是说,在使用模板类时,最好将它们保存为纯头文件。