我知道这个问题已经问过几次了,我一直在读类似的文章:
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<>
的使用。下面的代码似乎可以解决您的目标,它可以在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中的定义不需要模板<>?
根据17.7.3 [temp.expl.spec]第5段(N4659),[...]显式专门的类模板的成员在与普通班级成员的方式相同,但不使用template <>语法。当定义一个成员时也是如此明确专门的成员类。 [...][Note
,这并不是说问题中的代码是错误的,但是由于MSVC不满意(并且可能是错误的……?),因此,解决方法可能是上面建议的代码。] >