【问题标题】:Undefined reference to (g++ compilation with static library)未定义的引用(使用静态库的 g++ 编译)
【发布时间】:2013-04-06 12:31:39
【问题描述】:

项目文件如下:

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/。然后我运行了这个命令(密码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]

我该怎么办?

【问题讨论】:

  • 看来你是通过 header 和 source 使用模板,你需要在 header 中定义这些模板并包含它们。
  • 你能告诉我怎么做吗,这是我第一次使用模板,或者至少请参考一个教程。

标签: c++ g++ unix-ar


【解决方案1】:

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

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

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

将它们委托到单独的.cpp 文件中,编译器无法为您从包含其定义的翻译单元之外的其他翻译单元调用的成员函数生成代码。 This Q&A on StackOverflow 也可以帮到你。

【讨论】:

    【解决方案2】:

    我打赌你在.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。您会看到代码想要使用以T 实例化的test 模板作为int。所以现在您需要为test&lt;int&gt;::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 内的命名空间,则其行为未定义。

    【讨论】:

      【解决方案3】:

      你需要用你需要的类型声明一个brain模板类的实例,所以在brain.cpp文件的最后,你应该放:

      template class brain <long long> ;
      

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-12-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-04-01
        • 2017-02-08
        相关资源
        最近更新 更多