Class template static data-member definition/declaration/initialization

核能气质少年 提交于 2020-03-24 00:50:26

问题


I know that the question has been asked several times and I've been reading posts like:

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

However, I'm still struggling putting together all the pieces about templates, specializations, static data members definition and declarations.

What I have is something like:


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;
}

This code compiles on both GCC 9.2.0 and MSVC2015. Now, my understanding is that something like this, if included multiple times, may lead to multiple definitions of the same static variable since we have a complete specialization of the template. So the approach is to move this to a cpp file but keep a declaration of the specialization in the hpp. I'll do it a little more complicate by also adding a hpp file for the template implementation:

//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;
}

This code compiles fine on GCC9.2.0 but fails on MSVC2015 because of a redefinition of a1.

What is the correct way to do this? Why MSVC is complaining? Is there a way to make it correct and portable for all c++11-compliant compilers?

UPDATE: The first code does not provide right results on MSVC and it only shows zeros. In order to make it work properly I needed to take away "template<>" from the initialization of the static member. But this leads to non-compiling code in GCC.

UPDATE 2: I found basically the same question in here with a more complete analysis:

Resolving Definitions of Specialized Static Member Variables of Templated Classes

However nobody answered that question.


回答1:


You hit a bug in MSVC. It has apparently been fixed in Visual Studio 2019 version 16.5 Preview 2.

As an alternative workaround, you could leave your definitions in the header and mark them as inline (since 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};



回答2:


If you specialize the entire class you can omit the use of template<> in the cpp.

The code below seem to solve what you aim for, it compiles on MSVC (x86 V19.14), gcc (x86-64 9.2) and 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;
}

Why the definition in the cpp doesn't need template<>?

According to 17.7.3 [temp.expl.spec] paragraph 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. [...]

Note that this doesn't say that the code in the question is wrong, but since MSVC is not happy with it (and is probably wrong...?) the workaround might be the code proposed above.



来源:https://stackoverflow.com/questions/58583036/class-template-static-data-member-definition-declaration-initialization

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!