C ++函数模板专业化的可见性
假设我有fileA.h
,它使用模板函数SomeFunc <T>()
声明了一个类classA
。此功能直接在头文件中实现(与模板功能一样)。现在,我在文件A.C(即不在头文件中)中添加了一个SomeFunc()的特殊实现(例如,对于SomeFunc <int>())。
如果我现在从其他代码(也许也从另一个库)中调用SomeFunc <int>()
,它将调用通用版本还是专用版本?
我现在有这个问题,类和函数都存在于两个应用程序使用的库中。一个应用程序正确地使用了专业化,而另一个应用程序使用了通用形式(稍后会导致运行时问题)。为什么会有所不同?这可能与链接器选项等有关吗?这是在Linux上,带有g ++ 4.1.2.
解决方案
回答
除非头文件中也列出了专用模板功能,否则其他应用程序将不了解专用版本。解决方案是在标头中也添加SomeFunc <int>()
。
回答
我们是否已将带有参数的原型添加到头文件中?
我的意思是fileA.h中有某处
template<> SomeFunc<int>();
如果不是,那可能就是原因。
回答
布兰登:那就是我不应该调用专门功能的原因。对于我提到的第二个应用程序,这是正确的。但是,即使未在头文件中声明特殊化,第一个应用程序也明确地调用了特殊化形式!
我主要在这里寻求启发:-)因为第一个应用程序是单元测试,但是不幸的是,该错误没有出现在测试中,而是出现在真实的应用程序中...
(PS:实际上,已经通过在标头中声明了特殊性来修复此特定的错误;但是还有哪些其他类似的错误可能仍被隐藏?)
回答
根据规范,除非我们"导出"模板定义,否则专用功能模板永远不能在" fileA.C"外部调用。该模板定义目前尚无编译器(Comeau除外)支持(或者在可预见的将来进行了规划)。
另一方面,一旦实例化了函数模板,编译器就可以看到一个不再是模板的函数。 GCC可以在不同的编译器单元之间重用此定义,因为该标准规定,对于给定的一组类型参数[temp.spec],每个模板只能实例化一次。尽管如此,由于未导出模板,因此应将其限制为编译单元。
我认为,GCC可能会在共享各个编译单元的实例化模板列表时暴露一个错误。通常,这是一个合理的优化,但是应该考虑功能的特殊性,而这似乎做得并不正确。
回答
在Microsoft C ++中,我对内联函数进行了实验。我想知道如果我在其他来源中定义了不兼容版本的函数会发生什么。根据使用的是Debug版本还是Release版本,我得到不同的结果。在Debug中,编译器拒绝内联任何内容,并且无论源代码中的作用域如何,链接器都在链接相同版本的函数。在Release中,编译器内联了当时定义的任何版本,并且我们获得了该函数的不同版本。
两种情况都没有任何警告。我有点怀疑,这就是为什么我做这个实验。
我假设模板函数的行为与其他编译器相同。
回答
对在调用点不可见的模板进行专业化处理是错误的。不幸的是,不需要编译器来诊断此错误,然后可以对代码执行他们喜欢的操作(标准情况下,它是"格式错误,不需要诊断")。
从技术上讲,我们需要在头文件中定义特殊化,但是几乎每个编译器都会按照期望进行处理:这在C ++ 11中已通过新的" extern template"功能进行了修复:
extern template<> SomeFunc<int>();
这明确声明了特定的专业化定义在其他地方。许多编译器已经支持此功能,有些带有extern
。
回答
@ [安东尼·威廉姆斯],
我们确定不会将extern
模板声明与extern template
实例化混淆吗?据我所知,"外部模板"只能用于显式实例化,而不能用于专门化(这意味着隐式实例化)。 [temp.expl.spec]没有提到extern
关键字:
explicit-specialization: template < > declaration
回答
我在gcc4上遇到了同样的问题,这是我解决的方法。这比我之前的评论导致的解决方案更简单。先前的帖子想法是正确的,但是它们的语法对我不起作用。
----------header----------------- template < class A > void foobar(A& object) { std::cout << object; } template <> void foobar(int); ---------source------------------ #include "header.hpp" template <> void foobar(int x) { std::cout << "an int"; }