У меня есть шаблонный класс (Outer), и я хочу создать вложенный шаблонный класс на основе перечисления класса. Этот внутренний класс имеет статические переменные, поэтому, чтобы они были доступны, их необходимо определить вне класса.
template <class T>
class Outer
{
private:
enum InnerType {foo, bar /* etc */};
template <InnerType U>
class Inner
{
public:
static int x;
};
public:
// access Inner<>::x
void print() { std::cout << Inner<foo>::x << std::endl; }
};
// somehow define Inner<>::x
Я пробовал несколько разных вариантов синтаксиса в принятом ответе здесь, но, похоже, у меня не получается. Он компилируется, если я заменяю перечисление классом для каждого значения, но перечисление гораздо более явное. Можно ли здесь использовать перечисление?
Это нарушит инкапсуляцию и добавит геттер к вашему внешнему классу. Код, использующийOuter
, НИКОГДА не должен зависеть от внутреннего устройства класса. И это еще более справедливо в отношении глобальных переменных (которые являются статическими членами). Также в C++ используйте enum class
now и распечатайте (функции вывода также никогда не должны быть частью класса). Не расстраивайтесь из-за моих комментариев, я просто вижу здесь некоторые недостатки дизайна :)
Вы также можете использовать inline constexpr int x{42};
(из заголовочного файла, в противном случае используйте static constexpr
. Это вообще не сделает ее глобальной переменной (а будет константой времени компиляции), {42}
также присвоит значение (время компиляции).
Как я уже говорил, используйте inline
с C++17.
Я бы выбрал static inline int x = 42;
Демо
Кажется, я не могу заставить его работать. Опубликуйте дословное сообщение об ошибке, чтобы его можно было проиндексировать поисковыми системами, и ваш вопрос станет полезным для других пользователей, которые сталкиваются с подобными ошибками.
Думаю, вопрос достаточно ясен, чтобы на него можно было ответить. ОП хочет знать, как определить статический член вне шаблона класса.
Помните, что шаблон не является полным определением, он становится таковым только тогда, когда вы используете его с заполненным параметром шаблона.
поэтому их нужно будет определить вне класса
Это не обязательно так. В c++17 мы можем использовать inline
для предоставления определения внутри шаблона класса, как показано ниже.
Если вы используете стандарт до C++17, см. первое решение. Обратите внимание на использование ключевого слова enum
в версиях до C++17.
Итак, есть два способа решить эту проблему в зависимости от используемого вами стандарта С++, как показано ниже.
Здесь мы даем определение вне класса:
//-------------------------vvvv---------------------------->note this enum keyword
template<class T> template<enum Outer<T>::InnerType I> int Outer<T>::template Inner<I>::x =0;
Мы можем использовать inline
, чтобы предоставить определение внутри класса.
template <class T>
class Outer
{
private:
enum InnerType {foo, bar /* etc */};
template <InnerType U>
class Inner
{
public:
//--vvvvvv-------------------->with c++17
inline static int x = 0;
};
//other code as before
};
отклонено clang Демо
@ Jarod42 Jarod42 Да, я это видел, сообщаю об ошибке с лязгом. Размещу ссылку здесь.
@Jarod42 Jarod42 Вот ошибка clang: Clang отклоняет допустимый вне определения класса член статических данных шаблона вложенного класса
В зависимости от того, на какую версию стандарта C++ вы ориентируетесь, вы можете определить ее встроенным образом:
inline static int x = 0;
Обратите внимание, что это функция C++17.