假设我有fileA.h,它使用模板函数SomeFunc<T>()声明了一个类classA。此功能直接在头文件中实现(与模板功能一样)。现在,我在fileA.C(即不在头文件中)中添加了SomeFunc()的专用实现(例如对于SomeFunc<int>())。
如果我现在从其他代码(也许也从另一个库)调用SomeFunc<int>(),它将调用通用版本还是专业化版本?
我现在遇到这个问题,类和函数都存在于两个应用程序使用的库中。一个应用程序正确使用专业化,而另一个应用程序使用通用形式(稍后会导致运行时问题)。为什么会有所不同?可能与链接器选项等有关吗?这是在Linux上,带有g 4.1.2。
对在调用点不可见的模板进行专门化处理是错误的。不幸的是,编译器不需要诊断此错误,然后可以对您的代码执行他们喜欢的操作(标准的说法是"格式错误,无需诊断")。
从技术上讲,您需要在头文件中定义特殊化,但是几乎每个编译器都会按照您的期望进行处理:这在C 11中已通过新的"外部模板"功能进行了修复:
1
| extern template<> SomeFunc<int>(); |
这明确声明了特定专业在其他地方定义。许多编译器已经支持此功能,有些支持,有些不支持extern。
您是否已将带有参数的原型添加到头文件中?
我的意思是文件A.h中有某处
1
| template<> SomeFunc<int>(); |
如果不是,那可能就是原因。
我在gcc4上遇到了同样的问题,这是我如何解决的。这比我之前的评论使我相信的解决方案更简单。先前的帖子想法是正确的,但是它们的语法对我不起作用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| ----------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";
} |
根据规范,切勿在fileA.C之外调用专用功能模板,除非您export模板定义,当前没有编译器(除Comeau外)支持(或在可预见的将来计划了该模板定义)。铅>
另一方面,一旦实例化了功能模板,编译器就可以看到不再是模板的功能。 GCC可以在不同的编译器单元之间重用此定义,因为该标准规定,对于给定的一组类型参数[temp.spec],每个模板只能实例化一次。但是,由于未导出模板,因此应将其限制为编译单元。
我相信GCC在跨编译单元共享其实例化模板列表时可能会暴露一个错误。通常,这是一个合理的优化,但是应该考虑功能专业化,而这似乎并不能正确地完成。
正如Anthony Williams所说,extern template构造是执行此操作的正确方法,但是由于他的示例代码不完整并且有多个语法错误,因此这是一个完整的解决方案。
fileA.h:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| namespace myNamespace {
class classA {
public:
template <class T> void SomeFunc() { ... }
};
// The following line declares the specialization SomeFunc<int>().
template <> void classA::SomeFunc<int>();
// The following line externalizes the instantiation of the previously
// declared specialization SomeFunc<int>(). If the preceding line is omitted,
// the following line PREVENTS the specialization of SomeFunc<int>();
// SomeFunc<int>() will not be usable unless it is manually instantiated
// separately). When the preceding line is included, all the compilers I
// tested this on, including gcc, behave exactly the same (throwing a link
// error if the specialization of SomeFunc<int>() is not instantiated
// separately), regardless of whether or not the following line is included;
// however, my understanding is that nothing in the standard requires that
// behavior if the following line is NOT included.
extern template void classA::SomeFunc<int>();
} |
fileA.C:
1 2 3
| #include"fileA.h"
template <> void myNamespace::classA::SomeFunc<int>() { ... } |
在Microsoft C中,我对内联函数进行了实验。我想知道如果我在其他来源中定义了不兼容版本的函数会发生什么。根据使用的是Debug版本还是Release版本,我得到不同的结果。在Debug中,编译器拒绝内联任何内容,并且无论源代码中的作用域如何,链接器都在链接相同版本的函数。在Release中,编译器内联了当时定义的任何版本,并且您获得了该函数的不同版本。
在任何情况下都没有任何警告。我有点怀疑,这就是我进行实验的原因。
我假设模板函数的行为与其他编译器相同。
@ [安东尼·威廉姆斯],
您确定不会将extern模板声明与extern template实例化混淆吗?据我所知,extern template只能用于显式实例化,而不能用于专门化(这意味着隐式实例化)。 [temp.expl.spec]没有提及extern关键字:
explicit-specialization:
template < > declaration
布兰登:这就是我的想法-不应调用专用功能。对于我提到的第二个应用程序,这是正确的。但是,即使未在头文件中声明特殊化,第一个应用程序也显然会调用特殊化形式!
我主要在这里寻求启发:-),因为第一个应用程序是单元测试,但是不幸的是,这个错误没有出现在测试中,而是出现在真实的应用程序中...
(PS:我已经通过在标头中声明特殊性来修复此特定的错误;但是还有哪些其他类似的错误可能仍被隐藏?)
除非在头文件中还列出了专用模板功能,否则其他应用程序将不了解专用版本。解决方案是也将SomeFunc<int>()添加到标头中。