gpt4 book ai didi

C++模板函数在 header 中编译但未在实现中编译

转载 作者:IT老高 更新时间:2023-10-28 12:52:49 24 4
gpt4 key购买 nike

我正在尝试学习模板,但遇到了这个令人困惑的错误。我在头文件中声明了一些函数,我想创建一个单独的实现文件来定义这些函数。

这是调用 header 的代码(dum.cpp):

#include <iostream>
#include <vector>
#include <string>
#include "dumper2.h"

int main() {
std::vector<int> v;
for (int i=0; i<10; i++) {
v.push_back(i);
}
test();
std::string s = ", ";
dumpVector(v,s);
}

现在,这是一个有效的头文件(dumper2.h):

#include <iostream>
#include <string>
#include <vector>

void test();

template <class T> void dumpVector(const std::vector<T>& v,std::string sep);

template <class T> void dumpVector(const std::vector<T>& v, std::string sep) {
typename std::vector<T>::iterator vi;

vi = v.cbegin();
std::cout << *vi;
vi++;
for (;vi<v.cend();vi++) {
std::cout << sep << *vi ;
}
std::cout << "\n";
return;
}

有实现(dumper2.cpp):

#include <iostream>
#include "dumper2.h"

void test() {
std::cout << "!olleh dlrow\n";
}

奇怪的是,如果我将定义 dumpVector 的代码从 .h 移动到 .cpp 文件,我会得到以下错误:

g++ -c dumper2.cpp -Wall -Wno-deprecated
g++ dum.cpp -o dum dumper2.o -Wall -Wno-deprecated
/tmp/ccKD2e3G.o: In function `main':
dum.cpp:(.text+0xce): undefined reference to `void dumpVector<int>(std::vector<int, std::allocator<int> >, std::basic_string<char, std::char_traits<char>, std::allocator<char> >)'
collect2: ld returned 1 exit status
make: *** [dum] Error 1

那么为什么它以一种方式工作而不是另一种呢?明明编译器能找到test(),那为什么找不到dumpVector呢?

最佳答案

您遇到的问题是编译器不知道要实例化您的模板的哪个版本。当您将函数的实现移动到 x.cpp 时,它与 main.cpp 位于不同的翻译单元中,并且 main.cpp 无法链接到特定的实例化,因为它在该上下文中不存在。这是 C++ 模板的一个众所周知的问题。有几个解决方案:

1) 只需将定义直接放入 .h 文件中,就像您之前所做的那样。这有利有弊,包括解决问题(pro),可能使代码的可读性降低以及在某些编译器上更难调试(con),并且可能会增加代码膨胀(con)。

2) 将实现放在 x.cpp 中,#include "x.cpp"来自x.h .如果这看起来很时髦和错误,请记住 #include只是读取指定的文件并编译它就好像该文件是x.cpp 的一部分。 换句话说,这与上面的解决方案#1 完全相同,但它将它们保存在单独的物理文件中。在做这种事情时,不要尝试编译 #include 是至关重要的。 d 文件自己。出于这个原因,我通常给这类文件一个 hpp将它们与 h 区分开来的扩展名文件和来自 cpp文件。

文件:dumper2.h

#include <iostream>
#include <string>
#include <vector>

void test();
template <class T> void dumpVector( std::vector<T> v,std::string sep);
#include "dumper2.hpp"

文件:dumper2.hpp

template <class T> void dumpVector(std::vector<T> v, std::string sep) {
typename std::vector<T>::iterator vi;

vi = v.begin();
std::cout << *vi;
vi++;
for (;vi<v.end();vi++) {
std::cout << sep << *vi ;
}
std::cout << "\n";
return;

}

3) 因为问题是 dumpVector 的特定实例化尝试使用它的翻译单元不知道,您可以在与定义模板的翻译单元相同的翻译单元中强制对其进行特定实例化。只需添加以下内容:template void dumpVector<int>(std::vector<int> v, std::string sep); ...到定义模板的文件。这样做,您不再需要 #include hpp h 中的文件文件:

文件:dumper2.h

#include <iostream>
#include <string>
#include <vector>

void test();
template <class T> void dumpVector( std::vector<T> v,std::string sep);

文件:dumper2.cpp

template <class T> void dumpVector(std::vector<T> v, std::string sep) {
typename std::vector<T>::iterator vi;

vi = v.begin();
std::cout << *vi;
vi++;
for (;vi<v.end();vi++) {
std::cout << sep << *vi ;
}
std::cout << "\n";
return;
}

template void dumpVector<int>(std::vector<int> v, std::string sep);

顺便说一句,总而言之,您的模板函数采用 vector 按值。您可能不想这样做,而是通过引用或指针传递它,或者更好的是,传递迭代器以避免临时生成并复制整个 vector 。

关于C++模板函数在 header 中编译但未在实现中编译,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3040480/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com