1

项目文件是这样的:

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.a我将两者都复制brain.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]

我该怎么办?

4

3 回答 3

3

第一件事:不要将任何实体添加到std命名空间。这给你的程序Undefined Behavior

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

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

将它们放在一个单独的.cpp文件中会使编译器无法为您从其他翻译单元调用的成员函数生成代码,而不是包含它们的定义的翻译单元。StackOverflow 上的这个问答也可能对您有所帮助。

于 2013-04-06T12:34:50.550 回答
1

我打赌你brain.cpp文件中实现了类模板的成员函数。您需要在头文件中提供模板定义,以便编译器在看到模板实例时可以生成适当的代码。所以将brain.cppup 的内容移动到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. 您会看到代码想要使用用astest实例化的模板。所以现在您需要为 生成适当的代码,但要做到这一点,您需要查看函数的定义。不幸的是,你还没有看到它,所以你无法编译这个程序。Tinttest<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 或命名空间内的命名空间,则 C++ 程序的行为是未定义的,std除非另有说明。

于 2013-04-06T12:33:50.783 回答
1

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

template class brain <long long> ;

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

于 2013-04-06T12:36:02.347 回答