项目文件如下:
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.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]
我该怎么办?
答案 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时,除非你有模板说明符,否则它不会创建任何可链接的代码,因为它没有类型声明就无法实例化模板类。也就是说,在使用模板化类时,最好将它们保存为纯头文件