未定义的引用(使用静态库的g ++编译)

时间:2013-04-06 12:31:40

标签: c++ g++ ar

项目文件如下:

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.hpp复制到source/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]

我该怎么办?

3 个答案:

答案 0 :(得分:3)

首先:不要向std命名空间添加任何实体。这为您的程序提供了未定义的行为

在您的消息中,您似乎已将名为brain的类添加到std命名空间。从brain命名空间中删除std并将其放入您的某个命名空间中。您可以添加到std命名空间的唯一内容是属于std命名空间的模板的特化

其次,除非您提供在整个程序中使用的类模板的显式实例化您应该将类​​模板的成员函数的定义放在包含的同一个头文件中他们的声明,以确保它们在实例化点可见。

在单独的.cpp文件中删除它们使编译器无法为从包含其定义的其他翻译单元调用的成员函数生成代码。 This Q&A on StackOverflow也可以帮助您。

答案 1 :(得分:1)

我打赌你在brain文件中实现了类模板.cpp的成员函数。您需要在头文件中提供模板定义,以便编译器在看到模板实例时可以生成适当的代码。因此,请将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实例化的T模板作为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命名空间:

  

如果C ++程序向命名空间std或命名空间std中的命名空间添加声明或定义,则该行为是未定义的,除非另有说明。

答案 2 :(得分:1)

您需要使用您需要的类型声明大脑模板类的实例,因此在brain.cpp中,在文件的末尾,您应该放置:

template class brain <long long> ;

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