Определение / декларация / инициализация статического элемента данных шаблона класса - PullRequest
1 голос
/ 27 октября 2019

Я знаю, что вопрос задавался несколько раз, и я читал сообщения типа:

Инициализация статических членов шаблонного класса

Как я могу объявить / определить / инициализировать статическую переменную-член классов шаблонов как статические переменные-члены класса?

статическая инициализация члена для специализированного шаблонного класса

Однако я все еще изо всех сил пытаюсь собрать воедино все, что касается шаблонов, специализаций, определения членов статических данных и объявлений.

То, что у меня есть, выглядит примерно так:


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: я нашел в основном тот же вопрос здесь с более полным анализом:

Разрешение определений специализированных переменных статического членашаблонных классов

Однако никто не ответил на этот вопрос.

1 Ответ

1 голос
/ 28 октября 2019

Если вы специализируете весь класс, вы можете опустить использование template<> в cpp.

Код ниже, кажется, решает, к чему вы стремитесь, он компилируется в 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 не нужен шаблон <>?

Согласно пункту 5 раздела 17.7.3 [temp.expl.spec] ( N4659 ),

[...] Члены явно специализированного шаблона класса определяются так же, как и члены обычных классов, без использования синтаксиса шаблона <>. То же самое верно при определении члена явно специализированного класса члена. [...]

Обратите внимание , что это не говорит о том, что код в вопросе неверен, но поскольку MSVC недоволен им (и, вероятно, ошибается. ..?) Обходной путь может быть кодом, предложенным выше.

...