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

erroneous explicit template specialization of variable template in gcc

本文关键字:专用 变量 gcc 错误      更新时间:2023-10-16

//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中的一个错误吗?

整个问题有一个相当简单的解决方案。另外,请参阅ISO C++标准讨论论坛上的这篇文章和Richard Smith的回复。

1。不能在显式专用化中指定extern

因此,要回答最初的问题:不,这不是gcc中的错误,报告错误是正确的(正如Massimiliano Janes已经回答的那样)。

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

2。理论上(根据标准),解决方案是删除extern,因为与模板的链接是按名称命名的,因此专业化"继承"了主模板的链接(再次参见Massimiliano Janes的回答)

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

3。总结:

gcc从不编译(1)中正确但(2)中不正确的内容。clang在(1)中编译,这是不正确的,但在(2)中不编译,这也是不正确的。

我会为clang提交一份错误报告。如果有人感兴趣,请随时为gcc提交一个bug。我不会这么做,因为(不幸的是)我不能在我的开发环境VisualStudio中使用gcc。

主变量模板必须声明为extern,因为它是const,并且我不希望在头文件中使用初始值设定项(就像普通的"extern int const I;"一样)。相反,我想要一些源文件中的专业化定义。

解决方案应该是在专用化中删除"extern"。

因为

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

基本原理是所有专业化都应该具有相同的链接(例如,参见缺陷报告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;

根据N4340:

除thread_local之外的存储类说明符不应为在显式专业化(14.7.3)或显式实例化(14.7.2)指令。

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

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