0

很长一段时间以来,我一直在努力解决将模板化函数的实现与定义分开的老问题。C++0x'extern似乎是一个解决方案,但我无法正确应用它

我的代码:

main.cpp

#include <iostream>
#include <string>

#include "lexer.h"

int main(int argc, char const *argv[]) {
    std::string foo("foo");
    new lexer((foo.begin()),(foo.end()));
    return 0;
}

lexer.h

#ifndef lexer_h
#define lexer_h
class lexer {
    public:
    extern template<class InputIterator>
    lexer(InputIterator i, InputIterator end);
};
#endif //lexer_h

lexer.cpp

#include "lexer.h"
template<class InputIterator >
lexer::lexer(InputIterator i, InputIterator end) {
    //make it work
};

编译g++ main.cpp lexer.cpp -std=c++0x。我想稍后使用目标文件。

那么它看起来如何固定呢?

4

2 回答 2

1

除非您知道用作 参数的完整类型集,否则InputIterator定义需要进入头文件。

只有当您知道所需的完整实例化(参数)集时,模板定义(实现)才能与声明分开。编译器无法记住在一个.cpp(翻译单元)中使用了哪些实例化,并使用另一个.cpp.

正如 Andy 所提到的,您似乎正在寻找的行为以前被分配给 C++03export关键字,该关键字很少被实现,并且结果不如预期的有用,现在已完全从标准中删除。

如果您确实想走这条路(我现在正在编写一个类似的库!),extern关键字需要超出class {}范围,并且.cpp文件需要显式实例化所需的特化。

// header file

class lexer {
    public:
    template<class InputIterator>
    lexer(InputIterator i, InputIterator end);
};

extern template lexer::lexer( foo::iterator, foo::iterator );
extern template lexer::lexer( bar::iterator, bar::iterator );

// source file

template<class InputIterator >
lexer::lexer(InputIterator i, InputIterator end) {
    //make it work
};

template lexer::lexer( foo::iterator, foo::iterator );
template lexer::lexer( bar::iterator, bar::iterator );
于 2013-02-21T16:50:32.747 回答
0

它不起作用的原因是您没有实例化您的类模板,也没有实例化您的类模板的构造函数:在处理调用该构造函数.cpp以外的翻译单元(即文件)lexer.cpp时,编译器将无法查看它的定义,因此它不会为它发出任何目标代码;另一方面,在唯一可以看到其定义 ( lexer.cpp) 的翻译单元中,您没有调用构造函数,因此编译器也不会发出任何目标代码。

结果,您的程序的编译翻译单元中不存在您的构造函数的目标代码,并且链接器在尝试创建可执行文件时会抱怨对您的类的构造函数的未解析引用。

当您知道模板将(显式)在另一个翻译单元中实例化时,该extern关键字用于防止在一个翻译单元中实例化模板(即使其完整定义可见!) ,从而节省编译时间。有关说明,请参阅StackOverflow 上的此问答

来自 C++11 标准的第 14.7.2/2 段:

显式实例化的语法是:

显式实例化:extern(opt) 模板声明

显式实例化有两种形式:显式实例化定义和显式实例化声明。显式实例化声明extern关键字开头。

因此,您提供的只是一个声明。除非.cpp您在同一个翻译单元(唯一一个可以访问这些定义)。

C++03 有一个名为的关键字export,它允许执行您想要实现的目标,但在 C++11 的标准化过程中已将其删除,因为事实证明它对于编译器供应商来说难以实现。

于 2013-02-21T16:36:18.067 回答