类模板静态数据成员定义/声明/初始化
Class template static data-member definition/declaration/initialization
我知道这个问题已经被问了好几次了,我一直在读这样的帖子:
初始化模板类的静态成员
如何将模板类的静态成员变量声明/定义/初始化为类的静态会员变量?
专用模板类的静态成员初始化
然而,我仍在努力将有关模板、专业化、静态数据成员定义和声明的所有部分整合在一起。
我有一些类似的东西:
template<size_t dim>
struct A {
static std::array<float,dim> a1;
};
template<>
std::array<float,1U> A<1U>::a1{1.};
template<>
std::array<float,2U> A<2U>::a1{0.3,0.3};
int main() {
std::array<float, 1U> v1 = A<1U>::a1;
std::cout << v1[0] << std::endl;
std::array<float, 2U> v2 = A<2U>::a1;
std::cout << v2[0] << " " << v2[1] << std::endl;
return 0;
}
此代码在GCC 9.2.0和MSVC2015上进行编译。现在,我的理解是,如果多次包含这样的内容,可能会导致同一静态变量的多个定义,因为我们已经对模板进行了完全的专业化。因此,方法是将其移动到cpp文件中,但在hpp中保留专门化的声明。我将通过为模板实现添加一个hpp文件来使它稍微复杂一点:
//foo.hpp
template<size_t dim>
struct A {
static std::array<float, dim> a1;
};
#include "fooImpl.hpp"
//fooImpl.hpp
template<>
std::array<float, 1U> A<1U>::a1;
template<>
std::array<float, 2U> A<2U>::a1;
//foo.cpp
#include"foo.hpp"
template<>
std::array<float, 1U> A<1U>::a1{ 1. };
template<>
std::array<float, 2U> A<2U>::a1{ 0.3,0.3 };
//main.cpp
int main() {
std::array<float, 1U> v1 = A<1U>::a1;
std::cout << v1[0] << std::endl;
std::array<float, 2U> v2 = A<2U>::a1;
std::cout << v2[0] << " " << v2[1] << std::endl;
return 0;
}
此代码在GCC9.2.0上编译良好,但在MSVC2015上由于a1的重新定义而失败。
正确的方法是什么?MSVC为什么抱怨?有没有一种方法可以使它对所有符合c++11的编译器都是正确的和可移植的?
更新:第一个代码在MSVC上没有提供正确的结果,它只显示零。为了使其正常工作,我需要从静态成员的初始化中删除"template<>"。但这会导致GCC中的代码无法编译。
更新2:我在这里通过更完整的分析发现了基本相同的问题:
解析模板类的专用静态成员变量的定义
然而,没有人回答这个问题。
如果专门化整个类,则可以省略cpp中template<>
的使用。
下面的代码似乎解决了您的目标,它在MSVC(x86 V19.14(、gcc(x86-64 9.2(和clang(x86-64.9.0.0(上编译,在编译器资源管理器上测试:
template<size_t dim>
struct A {
static std::array<float,dim> a1;
};
template<>
struct A<1U> {
static std::array<float,1U> a1;
};
template<>
struct A<2U> {
static std::array<float,2U> a1;
};
// cpp
std::array<float,1U> A<1U>::a1 {1.f};
std::array<float,2U> A<2U>::a1 {0.3f,0.3f};
int main() {
std::array<float, 1U> v1 = A<1U>::a1;
std::cout << v1[0] << std::endl;
std::array<float, 2U> v2 = A<2U>::a1;
std::cout << v2[0] << " " << v2[1] << std::endl;
return 0;
}
为什么cpp中的定义不需要模板<>
根据17.7.3[温度解释规范]第5段(N4659(,
[…]显式专用类模板的成员在中定义与普通类的成员相同的方式,并且不使用模板<>语法。定义显式专门化的成员类。[…]
注意这并不是说问题中的代码是错误的,但由于MSVC对此不满意(可能是错误的…?(,解决方法可能是上面提出的代码。
您在MSVC中遇到了一个错误。它显然已在Visual Studio 2019 16.5预览版2中修复。
作为一种替代方法,您可以将定义保留在标头中,并将其标记为内联(自c++17以来(:
template<>
inline std::array<float,1U> A<1U>::a1{1.};
template<>
inline std::array<float,2U> A<2U>::a1{0.3,0.3};
- 如何声明特征矩阵,然后通过嵌套循环初始化它
- 在函数内部的声明中初始化数组,并在外部使用它
- 有没有办法一次声明相同类型的多个对象,并通过一个表达式立即使用相同的右值初始化它们?
- 构造函数/函数声明参数列表中的统一初始化
- 使用直接大括号初始化时,C++ 编译错误"声明末尾的预期";"
- 强制使用默认构造函数对成员进行未初始化的声明
- 无法在声明时使用初始值设定项列表初始化常量字符*/字符串数组的向量
- 初始化声明符是 prvalue 表达式吗?
- 智能指针可以单独向前声明和初始化吗?
- 在C++中,如果成员引用在其声明中初始化,为什么需要存储空间?
- C++ 通过函数声明后初始化向量
- public:静态常量字符串声明/初始化问题
- 类模板静态数据成员定义/声明/初始化
- 初始化的多维数组,用声明初始化和声明后初始化有什么区别
- 为什么允许在开关语句中声明变量?但不是声明 初始化
- WIA 2.0 - IWiaDevMgr2::GetImgDlg() - 如何声明/初始化 ppbstrFilePath
- (Qt C++)用值填充QMap,同时声明/初始化
- 变量声明初始化顺序
- 使用static、const、constexpr的全局声明/初始化
- c++中多个文件的声明/初始化问题