LINUX.ORG.RU

Инициализировать union константу в классе

 ,


0

1

Всем привет

Чувствую что туплю, потому прошу помощи - просветить.

Нужно сделать константу в классе, которая представляет из себя union. Сейчас это строка в самом низу:

static const TUnion A = TUnion(1,1);

(сорри за неинформативное имя)

Компилирую так:
$ g++ -std=c++14 -ggdb -o range range.cpp


Текущий вариант кода выдает такое:
test.cpp:74:36: error: ‘constexpr’ needed for in-class initialization of static data member ‘const TRangeLocation::TUnion TRangeLocation::A’ of non-integral type [-fpermissive]
  static const TUnion A = TUnion(1,1);
                                    ^
test.cpp:74:36: error: ‘constexpr TRangeLocation::TUnion::TUnion(TPointLocation::T, TPointLocation::T)’ called in a constant expression

Что ему нужно? Или вообще так нельзя?

Я ожидаю, что если я скормлю ему две единицы, то m_range константы TRangeLocation::A будет содержать 257.

#include <iostream>
#include <iomanip>
#include <cstdint> // uint8_t
#include <type_traits>

/**
 * \brief Definitions of constants for describing location of point relative of range's endpoints
 *
 * If was decided no not using enum since a bug in gcc: when defining bitsize of enum field, gcc emits warning: http://stackoverflow.com/questions/28401851/is-it-possible-to-specify-the-bit-width-of-an-enum-in-c11
 * All constants shall have same type
 * MAX shall contain maximum value
*/
class TPointLocation{ /// \todo: Rename to TPointRangeLocation
public:
	typedef uint8_t T; /// To let all constants have same type

	static const T LEFT_FROM = 0;  /// -p-f---t---
	static const T EQUAL_FROM = 1; /// ---fp--t---
	static const T BETWEEN = 2;    /// ---f-p-t---
	static const T EQUAL_TO = 3;   /// ---f---tp--
	static const T RIGHT_TO = 4;   /// ---f---t-p-

	static const T MAX = 4; /// Maximum value of all constants. Uses for static_assert.

	/// \todo: think about constexpr
};

/**
 * \brief Location of one range relative to another one.
*/
class TRangeLocation{ /// \todo: Rename to TRangeRangeLocation
public:
	typedef uint16_t T; /// Shall fit two TPointLocation::T

  /** \brief A structure just containing location information of two endpoints of the range.
	 *
	 * Used in union to construct cummulative value.
	 * Shall not be a bitfield, since later will use reference to it.
	 * Separated because a new struct cannot be defined in the union.
	*/
	struct TPoints{
		static_assert(std::is_integral<TPointLocation::T>::value && std::is_unsigned<TPointLocation::T>::value,"TPointLocation is expected to be an unsigned integer");
		//static_assert(TPointLocation::MAX < 9,"Bitfield size in not enough to store the value");
		static_assert(sizeof(T)==sizeof(TPointLocation::T)*2 ,"Size of TrangeLocation: is bigger (and thus causes ambiguity) or is not enough");
		TPointLocation::T from;
		TPointLocation::T to;

		constexpr TPoints():from(0),to(0){};
		constexpr TPoints(TPointLocation::T f, TPointLocation::T t):from(f),to(t){};
	};

	union TUnion{
		TPoints m_points; /// It is prefered to avoid constructions like m_points.from, but this is impossible
		T m_range;

		constexpr TUnion():m_range(0){};
		constexpr TUnion(TPointLocation::T from, TPointLocation::T to):m_points(from,to){};
	} m_value;

	const T &m_range = m_value.m_range; /// Convenient alias
	const TPointLocation::T &m_from = m_value.m_points.from; /// Convenient alias
	const TPointLocation::T &m_to = m_value.m_points.to;     /// Convenient alias

	TRangeLocation(){};
	TRangeLocation(TPointLocation::T from, TPointLocation::T to):m_value(from,to){};

	TRangeLocation& operator=(TRangeLocation &&b)
	{
		m_value.m_range = std::move(b.m_value.m_range);

		return *this;
	};

	static const TUnion A = TUnion(1,1);
} x;

int main()
{
	return 0;
};

★★★★★

Натыкался на подобные ошибки, но не с классами, а с обычными int или double статическими константами. Причем в одних классах это считалось нормальным, в других - компилятор выдавал такую же ошибку.

В моих примерах нашел два варианта решения проблемы:

1) Перемещение определения константы из описания твоего класса в .h файле в глобальную область в .cpp файле

 const int TRangeLocation::A = TUnion(1,1); 
2) В принципе совсем не вариант, но у меня сработало - убрать отладочную информацию и собрать с опцией -O2

Burns
()

Статические члены класса должны инициироваться вне определения. Например, у тебя есть класс:

class A
  {
	private:
		static int m_variable;
	…
  }
Чтобы инициировать переменную, тебе нужно сделать int A::m_variable = 0; за пределами класса (как описания, так и определений функций)

XMs ★★★★★
()
Ответ на: комментарий от XMs

Советую обратить внимание на то, что при инициации указывается тип, как при объявлении. Дело в том, что под статичные члены класса память не выделяется, и её надо выделить вручную

XMs ★★★★★
()

Потому что стандарт в пунткте 9.4.2 параграфе 3 указывает

If a non-volatile const static data member is of integral or enumeration type, its declaration in the class definition can specify a brace-or-equal-initializer in which every initializer-clause that is an assignmentexpression is a constant expression (5.20). A static data member of literal type can be declared in the class definition with the constexpr specifier; if so, its declaration shall specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression. [ Note: In both these cases, the member may appear in constant expressions. —end note ] The member shall still be defined in a namespace scope if it is odr-used (3.2) in the program and the namespace scope definition shall not contain an initializer.

Uter
()
Ответ на: комментарий от Burns

1) Перемещение определения константы из описания твоего класса в .h файле в глобальную область в .cpp файле

Сработало!
Говорю ж: туплю.
Сбило с толку, что в class TPointLocation объявлял такие константы внутри.

Спасибо большое!

Kroz ★★★★★
() автор топика

TPointLocation

Зачем префиксы у типов? Классы от интерфейсов отличать? Или просто Delphi-травма?

mix_mix ★★★★★
()
Ответ на: комментарий от Kroz

Отличать от не-типов.

А переменные тоже с большой буквы именуешь? Или такое различие считаешь недостаточным?

DarkEld3r ★★★★★
()
Ответ на: комментарий от DarkEld3r

А переменные тоже с большой буквы именуешь? Или такое различие считаешь недостаточным?

Нет, переменные с маленькой. Функции с большой.

Kroz ★★★★★
() автор топика
Ответ на: комментарий от DELIRIUM

Идешь в секцию бинаря со станичными данными, садишься и выделяешь, пока все не выделишь.

anonymous
()
Ответ на: комментарий от DELIRIUM

A static data member is not part of the subobjects of a class. There is only one copy of a static data member shared
by all the objects of the class

Из этого следует, что при создании экземпляра класса память для статических членов не выделяется, только память на ссылку. По крайней мере, я это так понимаю. Поправь, если ошибаюсь

XMs ★★★★★
()
Ответ на: комментарий от XMs

Немного не так. Это как бы одна переменная расшаренная между всеми объектами класса. Она по идее даже не входит в размер объекта. Можно ее рассматривать как глобальную переменную в namespace совпадающем с именем класса; вот только в классе к ней можно обращаться без указания namespace, как к переменной-члену класса.
В объектах нет на нее ссылок.

Kroz ★★★★★
() автор топика
Ответ на: комментарий от Kroz

Можно ее рассматривать как глобальную переменную в namespace совпадающем с именем класса
В объектах нет на нее ссылок

Даже так. Благодарю, буду знать

XMs ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.