假设我fileA.h
声明了一个带有模板函数classA
的类SomeFunc<T>()
。此函数直接在头文件中实现(通常用于模板函数)。现在,我在SomeFunc()
中添加SomeFunc<int>()
的专门实现(例如fileA.C
}(即不在头文件中)。
如果我现在从其他代码(可能还有其他库)调用SomeFunc<int>()
,它会调用泛型版本还是专门化版本?
我现在遇到这个问题,其中类和函数存在于两个应用程序使用的库中。一个应用程序正确使用专门化,而另一个应用程序使用通用形式(稍后会导致运行时问题)。为什么不同?这可能与链接器选项等有关吗?这是在Linux上,使用g ++ 4.1.2。
答案 0 :(得分:22)
错误,对于在通话点处不可见的模板具有专门性。遗憾的是,编译器不需要诊断此错误,然后可以使用您的代码执行他们喜欢的操作(在标准中它“形成错误,无需诊断”)。
从技术上讲,你需要在头文件中定义特化,但几乎每个编译器都会像你期望的那样处理它:这在C ++ 11中使用新的“extern模板”工具修复:
extern template<> SomeFunc<int>();
这明确声明特定的特化在别处定义。许多编译器已经支持这一点,有些编译器支持,有些没有extern
。
答案 1 :(得分:9)
您是否已将带参数的原型添加到头文件中?
我的意思是在fileA.h中有某处
template<> SomeFunc<int>();
如果不是那可能是原因。
答案 2 :(得分:3)
我和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";
}
答案 3 :(得分:2)
根据规范,您的专用函数模板永远不应在fileA.C
之外调用,除非您export
模板定义,没有编译器(Comeau除外)当前支持(或者计划用于可预见的)未来的)。
另一方面,一旦实例化了函数模板,编译器就会看到一个不再是模板的函数。 GCC可以在不同的编译器单元中重用这个定义,因为标准规定每个模板只能为给定的一组类型参数[temp.spec]实例化一次。但是,由于模板未导出,因此应仅限于编译单元。
我相信GCC可能会在编译单元中共享其实例化模板列表时暴露一个错误。通常情况下,这是一个合理的优化,但它应该考虑功能特化,而这似乎没有正确。
答案 4 :(得分:1)
正如Anthony Williams所说,extern template
构造是正确的方法,但由于他的示例代码不完整且有多个语法错误,所以这是一个完整的解决方案。
fileA.h:
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:
#include "fileA.h"
template <> void myNamespace::classA::SomeFunc<int>() { ... }
答案 5 :(得分:0)
除非头文件中还列出了专用模板功能,否则其他应用程序将不知道专用版本。解决方案是在标题中添加SomeFunc<int>()
。
答案 6 :(得分:0)
我主要在这里寻求启发:-)因为第一个应用程序是一个单元测试,不幸的是有一个没有出现在测试中但在真实应用程序中的错误......
(PS:我已经修复了这个特定的错误,实际上是通过声明标题中的特化;但是其他类似的错误仍然可能被隐藏?)
答案 7 :(得分:0)
在Microsoft C ++中,我使用内联函数进行了实验。我想知道如果我在不同的源中定义了不兼容的函数版本会发生什么。根据我是使用Debug构建还是Release构建,我得到了不同的结果。在Debug中,编译器拒绝内联任何内容,并且链接器链接相同版本的函数,无论源中的范围是什么。在Release中,编译器内联了当时定义的任何版本,并且您有不同版本的函数。
在任何情况下都没有任何警告。我有点怀疑这个,这就是我做实验的原因。
我认为模板函数的行为与其他编译器的行为相同。
答案 8 :(得分:0)
@ [安东尼 - 威廉姆斯]
您确定不会将extern
模板声明与extern template
实例化混淆吗?根据我的看法,extern template
可能仅用于显式实例化,而不是用于特化(这意味着隐式实例化)。 [temp.expl.spec]未提及extern
关键字:
明确分工:
template
&lt; &GT; 声明