我知道这个问题已经被问过好几次了,我一直在阅读这样的帖子:
Initializing static members of a templated class
static member initialization for specialized template class
但是,我仍在努力将有关模板、特化、静态数据成员定义和声明的所有部分组合在一起。
我有这样的东西:
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: 我在这里找到了基本相同的问题,并进行了更完整的分析:
Resolving Definitions of Specialized Static Member Variables of Templated Classes
但是没有人回答这个问题。
最佳答案
如果对整个类进行特化,则可以省略 template<>
的使用在 cpp 中。
下面的代码似乎可以解决您的目标,它在 MSVC (x86 V19.14)、gcc (x86-64 9.2) 和 clang (x86-64 9.0.0) 上编译 as tested on Compiler Explorer :
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中的定义不需要template<>?
根据 17.7.3 [temp.expl.spec] 第 5 段 ( N4659 ),
[...] Members of an explicitly specialized class template are defined in the same manner as members of normal classes, and not using the template<> syntax. The same is true when defining a member of an explicitly specialized member class. [...]
注意 这并不是说问题中的代码是错误的,但是由于 MSVC 对此不满意(并且可能是错误的......?)解决方法可能是代码上面提出。
关于c++ - 类模板静态数据成员定义/声明/初始化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58583036/