具有可变参数的外部模板无法编译

Zhe*_*hen 3 c++ templates variadic-templates c++11

我尝试使用可变参数创建一个extern模板,如:

extern template<typename... XS> void log( XS... xs );
Run Code Online (Sandbox Code Playgroud)

但是gcc 7.2没有编译它,并显示错误:

error: expected unqualified-id before ‘<’ token
Run Code Online (Sandbox Code Playgroud)

我在c ++ 11中检查gcc状态,extern模板应该可以工作,不是吗?

And*_*owl 7

extern关键字做一些事情比你预期不同的-如果我理解正确的话,你所期望的,当然.

extern关键字应用于模板的显式实例化,并且它可以防止编译器在处理某个转换单元时隐式生成该模板的代码.根据C++ 11标准的第14.7.2/2段:

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

如果没有extern关键字,编译器会log(double, int)在每个包含调用的转换单元中生成(比方说)log(double, int)代码,并且此代码 - 对于所有转换单元应该是相同的 - 最终将由链接器合并(链接器基本上会丢弃)所有重复,只保留一个).

extern通过告诉编译器,该关键字可以避免编译时间浪费:" 相信我,别人会在其他地方实例化这个模板 - 你现在不需要这样做 ".但必须履行这一承诺.

例如,如果您有这个主要模板:

template<typename... Xs> void log(Xs... xs);
Run Code Online (Sandbox Code Playgroud)

并声明这个显式实例化:

extern template void log(int, double);
Run Code Online (Sandbox Code Playgroud)

在某些翻译单元中,您必须具有相应的显式实例化:

template void log(int, double)
Run Code Online (Sandbox Code Playgroud)

否则,编译器永远不会为其生成代码log<int, double>(int, double),并且链接器会抱怨未定义的引用.

  • @Zhen:是的,遗憾的是,您可以将模板定义放在`.cpp`文件中的唯一情况是为所有模板实例创建显式实例化,否则将隐式生成.C++ 03有一个名为`export`的关键字,旨在解决这个问题,但事实证明它对编译器供应商来说太难了(只有基于EDG的编译器),所以它在C++ 11中被删除了. (2认同)