gcc中变量模板的错误显式模板特化

时间:2017-10-15 07:26:53

标签: c++ gcc clang c++14 c++17

// i.h

template<int> extern int const i;

// i.cpp

#include "i.h"
template<> extern int constexpr i<0> = 42;

// main.cpp

#include "i.h"
int main()
{
  return i<0>;
}

在C ++ 14/17模式下,这会返回带有clang的42,但是gcc是错误的:“显式模板专门化不能有存储类”。

这是gcc中的错误吗?

3 个答案:

答案 0 :(得分:2)

对整个问题有一个相当简单的解决方案。另请参阅ISO C ++标准的this帖子 - 讨论论坛和Richard Smith的回复。

1。 不得在显式专业化

中指定extern

所以回答原来的问题:不,这不是gcc中的错误,报告错误是正确的(正如Massimiliano Janes已经回答的那样)。

相比之下 clang实际上有一个错误(正如Massimiliano Janes已经猜到的那样)因为extern被接受了。也许clang默默地接受它,因为它与主模板的相同。

2。 从理论上讲(根据标准),解决方案是删除extern,因为模板链接是按名称进行的,因此专业化会继承&#39;主要模板的联系(再次参见Massimiliano Janes&#39;回答)

但在实践中它不起作用,因为这两个编译器都不正确,并且显式专业化错误地具有内部链接而不是外部主模板的链接。

3。 总结:

gcc从不编译哪个在(1)中是正确的但在(2)中是不正确的。 clang在(1)中编译,这是不正确的,但在(2)中没有编译,这也是不正确的。

我将为clang提交错误报告。如果有人有兴趣,请随时为gcc提交错误。我不会这样做,因为(不幸的是)我不能在我的开发环境Visual Studio中使用gcc。

答案 1 :(得分:1)

  

主变量模板必须声明为extern,因为它是const而且我不想在头文件中使用初始化器(就像普通的“extern int const i;”一样)。相反,我想在某些源文件中使用特化定义。

解决方案应该是将'extern'放在专业化中。

,因为

  

[declarations / specifiers-7.1.1]不应在显式专门化中指定存储类说明符

理由是所有专业化应该具有相同的链接(例如参见defect report 605)。所以,这里的铿锵似乎是错误的。

无论如何,鉴于编译器对此表现得很疯狂,解决方法可能类似于

// i.h
template<int I> struct i_impl{ static const int value; };
template<int I> int const i = i_impl<I>::value;

// i.cpp
#include <i.h>
template<> const int i_impl<0>::value = 42;

答案 2 :(得分:0)

根据N4340

  

存储类说明符不是thread_local   在显式专门化(14.7.3)中指定或显式   实例化(14.7.2)指令。

因此,extern说明符会发生这种情况。只需删除specialization上的任何存储说明符。在代码中删除extern说明符。如:

template<> 
int constexpr i<0> = 42;