gcc中变量模板的错误显式模板专用化
erroneous explicit template specialization of variable template in gcc
//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;
- 成员变量如何使用专用类模板?
- 变量模板的部分专用化
- 模板变量的显式专用化
- 如何从具有专用化的类模板定义静态成员变量?
- 变量模板专用化
- 如果参数具有成员变量,则专用化函数
- 变量模板的显式专用化
- C++类模板专用变量
- 指针和 c 样式数组变量的专用模板
- 禁用成员函数和变量,而不使用继承或类专用化
- gcc中变量模板的错误显式模板专用化
- 类模板专用化中的成员变量别名
- 具有 std::enable_if 的多变量模板专用化
- C++ 使类的成员变量成为子类中的专用化
- c++ 如何初始化部分模板专用化的静态变量
- 如果实例化,如何使模板化变量专用化在编译时失败
- 如何在同一成员变量中存储不同的专用模板类
- 访问专用模板的私有/继承成员变量
- C++1y/C++14:变量模板专用化
- 模板成员变量专用化