3

The following function template with specializations should be used within the same .cpp file only, so I’d like to make it static. The following code compiles (without warnings) using both MS Visual C++ 2008 and GCC 4.8.1 and works as intended. (Adding static to the beginning of lines 5 and 11 would cause GCC to issue an error but not MSVC.)

 1  template <class T>
 2  static bool foo(const T param);
 3
 4  template <>
 5  bool foo<int>(const int param)
 6  {
 7      return doSomethingWithInt(param);
 8  }
 9
10  template <>
11  bool foo<bool>(const bool param)
12  {
13      return doSomethingWithBool(param);
14  }

However, MISRA C++ checker complains:

  • (MISRA2008.3-3-2) Apply the static keyword to declaration of 'foo' (1)
  • (MISRA2008.3-3-2) Apply the static keyword to declaration of 'foo' (5)
  • (MISRA2008.2-10-5-b) Identifier 'foo' is being reused (5)
  • (MISRA2008.3-3-2) Apply the static keyword to declaration of 'foo' (11)
  • (MISRA2008.2-10-5-b) Identifier 'foo' is being reused (11)

I tried to find out what’s wrong and found a hint in a C++ standard quote:

For a function call that depends on a template parameter, if the function name is an unqualified-id but not a template-id, the candidate functions are found using the usual lookup rules (3.4.1, 3.4.2) except that:

  • For the part of the lookup using unqualified name lookup (3.4.1), only function declarations with external linkage from the template definition context are found.

Does it mean that the compilers discard the static specification and there is no way to actually make static function templates in C++03?

4

1 回答 1

1

显式特化使函数(或类)的定义能够根据模板特化的模板参数进行更改。它们不是“新声明”。

GCC 正确警告static在显式专业化 7.1.1/1 上的使用:

不应在显式特化 (14.7.3) 或显式实例化 (14.7.2) 指令中指定存储类说明符。

因此,对于 5 和 11,您的 MISRA 检查器提出的应用“静态”的建议似乎是错误的,我也会质疑它foo以某种方式被重用。只有一个实体foo恰好有不同的定义。

具有内部链接的功能在此翻译单元之外不可见。仅当重载决议选择了主模板本身后,才考虑显式特化。

考虑以下:

template <typename T>
void f (T);              // #1

template <>
void f<int*> (int*);     // #2

template <typename T>
void f (T*);             // #3

void b() {
  int * i;
  f(i);                  // Calls #3
}

查找f查找两个模板 #1 -f(T)和 #3 - f(T*)T推导出int*#1 和int#3 (14.8.2)。f(int*)使用特化 #1 ->和 #3 ->进行重载解决f(int*)。两者都不是最佳匹配,因此会发生部分排序(14.5.6.2)。偏序的结果是 #3 比 #1 更专业。因此编译器选择#3 作为最佳匹配。 注意:显式专业化没有参与上述任何步骤。

如果没有#3。然后#1将被重载决议选为最佳匹配。然后编译器搜索特化列表。推导的参数列表int*与显式规范中使用的参数列表匹配,因此调用定义#2。

关于引用的段落:

  • 对于使用非限定名称查找 (3.4.1) 的查找部分,仅找到具有来自模板定义上下文的外部链接的函数声明。

此限制起源于可以导出模板时 (C++ '03 14/6)。这个想法是允许在当前翻译单元之外定义模板。此查找限制将有助于确保更改要导出的未导出模板不会导致不同的含义程序。

关于您关于这对静态函数模板和 C++ '03 意味着什么的问题,现实情况是,据我所知,只有一家编译器供应商曾完全实现导出模板。无论如何,大多数编译器供应商很可能在很长一段时间内都遵循 C++ 11 的建议。从 MISRA 合规性的角度来看,最好的选择是遵循金属对您问题的评论中的建议。将模板放在未命名的命名空间中。

在 C++ '03 中,名称将无法从翻译单元外部调用,对于 C++ '11 及更高版本,它们具有隐式内部链接 (3.5/4):

未命名的命名空间或在未命名的命名空间中直接或间接声明的命名空间具有内部链接。

于 2015-07-27T12:16:54.597 回答