c++ - 类模板静态数据成员定义/声明/初始化

标签 c++ c++11 template-specialization static-members

我知道这个问题已经被问过好几次了,我一直在阅读这样的帖子:

Initializing static members of a templated class

How can I Declare/define/initialize a static member variable of template classes as static member variables of a 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/

相关文章:

c++ - 在 C++11 中的类中的不同方法之间共享 random_number_engine

c++ - 当不支持可变模板参数时,如何为元组专门化类模板?

c++ - 直接执行数据

c++ - 在 OPENMP 中并行添加矩阵 vector

c++ - C 不支持通过引用传递变量。怎么做?

c++ - 如何让编译器使用正确的模板特化?

c++ - 具有从属名称(类型名)的部分特化

c++ - 两个线程共享变量

c++11 - C++11 是否有像 Boost 的scoped_array 这样的动态分配数组的包装器?

C++11 错误不匹配调用 main 之外的 Ifstream