Инициализация члена const в объявлении класса в С++
В PHP и С# константы могут быть инициализированы по мере их объявления:
class Calendar3
{
const int value1 = 12;
const double value2 = 0.001;
}
У меня есть следующее объявление С++ функтора, который используется с другим классом для сравнения двух математических векторов:
struct equal_vec
{
bool operator() (const Vector3D& a, const Vector3D& b) const
{
Vector3D dist = b - a;
return ( dist.length2() <= tolerance );
}
static const float tolerance = 0.001;
};
Этот код скомпилирован без проблем с g++. Теперь в режиме С++ 0x (-std = С++ 0x) компилятор g++ выводит сообщение об ошибке:
error: 'constexpr, необходимый для инициализации класса статических данных в классе, для нецелого типа
Я знаю, что могу определить и инициализировать этого члена static const
вне определения класса. Кроме того, нестатический элемент данных констант может быть инициализирован в списке инициализаторов конструктора.
Но есть ли способ инициализировать константу в объявлении класса так же, как это возможно в PHP или С#?
Update
Я использовал ключевое слово static
только потому, что было возможно инициализировать такие константы в объявлении класса в g++. Мне просто нужен способ инициализации константы в объявлении класса независимо от того, объявлен ли он как static
или нет.
Ответы
Ответ 1
В С++ 11 члены класса non static
, члены данных static constexpr
и static const
члены данных интегрального или перечисляющего типа могут быть инициализированы в объявлении класса. например.
struct X {
int i=5;
const float f=3.12f;
static const int j=42;
static constexpr float g=9.5f;
};
В этом случае член i
всех экземпляров класса X
инициализируется в 5
конструктором, сгенерированным компилятором, и член f
инициализируется на 3.12
. Элемент данных static const
j
инициализируется значением 42
, а элемент данных static constexpr
g
инициализируется значением 9.5
.
Так как float
и double
не являются целыми или перечисляемыми типами, такие члены должны либо быть constexpr
, либо не static
, чтобы инициализатор в определении класса был разрешен.
До С++ 11 только члены static const
данных интегрального типа или типа перечисления могли иметь инициализаторы в определении класса.
Ответ 2
Инициализация статических переменных-членов, отличных от типов const int, не является стандартным С++ до С++ 11. Компилятор gcc не будет предупреждать вас об этом (и, тем не менее, создавать полезный код), если вы не укажете опцию -pedantic
. Затем вы должны получить ошибку, аналогичную:
const.cpp:3:36: error: floating-point literal cannot appear in a constant-expression
const.cpp:3:36: warning: ISO C++ forbids initialization of member constant ‘tolerance’ of non-integral type ‘const float’ [-pedantic]
Причиной этого является то, что стандарт С++ не указывает, как должна выполняться функция с плавающей запятой и оставлена для процессора. Чтобы обойти это и другие ограничения constexpr
, был введен.
Ответ 3
Да. Просто добавьте ключевое слово constexpr
, как говорит ошибка.
Ответ 4
Если вам нужен только один метод, вы можете объявить его локально статическим:
struct equal_vec
{
bool operator() (const Vector3D& a, const Vector3D& b) const
{
static const float tolerance = 0.001f;
Vector3D dist = b - a;
return ( dist.length2() <= tolerance );
}
};
Ответ 5
Я столкнулся с реальными проблемами с этим, потому что мне нужен тот же код для компиляции с разными версиями g++ (компилятор GNU С++). Поэтому мне пришлось использовать макрос, чтобы посмотреть, какая версия компилятора была использована, а затем действовать соответственно так:
#if __GNUC__ > 5
#define GNU_CONST_STATIC_FLOAT_DECLARATION constexpr
#else
#define GNU_CONST_STATIC_FLOAT_DECLARATION const
#endif
GNU_CONST_STATIC_FLOAT_DECLARATION static double yugeNum=5.0;
Это будет использовать 'const' для всего до g++ версии 6.0.0, а затем использовать 'constexpr' для g++ версии 6.0.0 и выше. Это предположение о версии, где происходит изменение, потому что, честно говоря, я не заметил этого до версии g++ 6.2.1. Чтобы сделать это правильно, вам, возможно, придется посмотреть на младшую версию и номер патча g++, поэтому см.
https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html
для получения сведений о доступных макросах.
С помощью gnu вы также можете использовать 'const' всюду, а затем скомпилировать с флагом -fpermissive
, но это дает предупреждения, и мне нравится, когда мои вещи компилируются чисто.
Невероятно, потому что он специфичен для компиляторов gnu, но я подозреваю, что вы могли бы сделать подобное с другими компиляторами.
Ответ 6
Ну, не совсем прямой ответ, но какая-то конкретная причина не использовать макрос?
#define tolerance 0.001
struct equal_vec
{
bool operator() (const Vector3D& a, const Vector3D& b) const
{
Vector3D dist = b - a;
return ( dist.length2() <= tolerance );
}
};
Не совсем хорошая практика С#, но IMHO совершенно законна в С++.