25

假设我fileA.h声明了一个classA带有模板函数的类SomeFunc<T>()。该函数直接在头文件中实现(与模板函数一样)。现在,我在(即不在头文件中)添加了SomeFunc()(如 for SomeFunc<int>())的专门实现。fileA.C

如果我现在SomeFunc<int>()从其他代码(可能也来自另一个库)调用,它会调用通用版本还是专业化版本?

我现在有这个问题,类和函数存在于两个应用程序使用的库中。一个应用程序正确地使用了专业化,而另一个应用程序使用了通用形式(这会导致稍后出现运行时问题)。为什么有区别?这可能与链接器选项等有关吗?这是在 Linux 上,使用 g++ 4.1.2。

4

9 回答 9

23

对在调用点不可见的模板进行专门化是错误的。不幸的是,编译器不需要诊断这个错误,然后可以用你的代码做他们喜欢的事情(在标准中它是“格式错误,不需要诊断”)。

从技术上讲,您需要在头文件中定义特化,但几乎每个编译器都会按照您的预期处理这个问题:这在 C++11 中通过新的“外部模板”工具修复:

extern template<> SomeFunc<int>();

这明确声明特定专业化在其他地方定义。许多编译器已经支持这一点,有些有,有些没有extern.

于 2008-09-12T16:14:26.313 回答
9

您是否在头文件中添加了带有参数的原型?

我的意思是在fileA.h中的某个地方

template<> SomeFunc<int>();

如果不是这可能是原因。

于 2008-09-12T15:44:57.757 回答
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";
    }

于 2009-04-24T18:50:39.470 回答
2

根据规范,您的专用函数模板永远不应该在外部调用fileA.C,除非您export的模板定义目前没有编译器(Comeau 除外)支持(或计划在可预见的未来使用)。

另一方面,一旦函数模板被实例化,编译器就会看到一个不再是模板的函数。GCC 可以在不同的编译器单元中重复使用这个定义,因为标准规定每个模板只能针对给定的一组类型参数 [temp.spec] 实例化一次。尽管如此,由于没有导出模板,这应该仅限于编译单元。

我相信 GCC 可能会在跨编译单元共享其实例化模板列表时暴露一个错误。通常,这是一个合理的优化,但它应该考虑到它似乎没有正确执行的函数专业化。

于 2008-09-12T15:59:00.547 回答
1

在 Microsoft C++ 中,我用内联函数做了一个实验。我想知道如果我在不同的来源中定义了不兼容的函数版本会发生什么。根据我使用的是 Debug 构建还是 Release 构建,我得到了不同的结果。在 Debug 中,编译器拒绝内联任何内容,并且链接器正在链接相同版本的函数,无论源代码中的范围是什么。在 Release 中,编译器内联了当时定义的任何版本,并且您得到了不同版本的函数。

在这两种情况下都没有任何警告。我有点怀疑这一点,这就是我做这个实验的原因。

我假设模板函数的行为与其他编译器一样。

于 2008-09-12T16:10:25.777 回答
1

正如 Anthony Williams 所说,extern template构造是执行此操作的正确方法,但由于他的示例代码不完整并且有多个语法错误,这里有一个完整的解决方案。

文件A.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>();
}

文件AC:

#include "fileA.h"

template <> void myNamespace::classA::SomeFunc<int>() { ... }
于 2013-09-11T13:24:36.677 回答
0

除非头文件中还列出了专用模板功能,否则其他应用程序将不知道专用版本。解决方案也是添加SomeFunc<int>()到标题中。

于 2008-09-12T15:43:32.690 回答
0

Brandon:这就是我的想法——永远不应该调用专门的函数。我提到的第二个应用程序也是如此。然而,第一个应用程序清楚地调用了专门化形式,即使在头文件中没有声明专门化!

我主要在这里寻求启发:-)因为第一个应用程序是单元测试,不幸的是有一个没有出现在测试中但在真实应用程序中出现的错误......

(PS:我已经修复了这个特定的错误,实际上是通过在标题中声明专业化;但是还有哪些其他类似的错误可能被隐藏?)

于 2008-09-12T15:47:38.327 回答
0

@[安东尼-威廉姆斯],

您确定没有将extern模板声明与extern template实例化混淆吗?从我所见,extern template只能用于显式实例化,而不用于专门化(这意味着隐式实例化)[temp.expl.spec] 没有提到extern关键字:

显式专业化
    template< >声明

于 2008-09-12T16:35:47.697 回答