Инициализация члена const в объявлении класса В C++
в PHP и C# константы могут быть инициализированы так, как они объявлены:
class Calendar3
{
const int value1 = 12;
const double value2 = 0.001;
}
у меня есть следующее объявление c++ функтора, который используется с другим классом Для сравнения двух математических векторов:
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++. Теперь в режиме C++0x (-std=c++0x) компилятор g++ выводит сообщение об ошибке:
ошибка: 'constexpr' необходимо для инициализации в классе статического члена данных 'допуск' не-интегрального типа
Я знаю, что могу определить и инициализировать это static const
член вне определения класса. Кроме того, нестатический постоянный элемент данных может быть инициализирован в списке инициализаторов конструктора.
но есть ли способ инициализировать константу в объявлении класса так же, как это возможно в PHP или C#?
обновление
Я static
ключевое слово только потому, что можно было инициализировать такие константы в пределах объявление класса в G++. Мне просто нужен способ инициализировать константу в объявлении класса, независимо от того, объявлен ли он как static
или нет.
6 ответов:
в C++11, не
static
данные-члены,static constexpr
данные-члены, иstatic const
элементы данных типа integral или перечисления могут быть инициализированы в объявлении класса. например,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
для того, чтобы инициализатор в определении класса должны быть разрешены.до C++11, всего
static const
элементы данных типа integral или перечисления могут иметь инициализаторы в определении класса.
инициализация статических переменных-членов, отличных от типов const int, не является стандартным C++ до C++11. Компилятор gcc не предупредит вас об этом (и тем не менее создаст полезный код), если вы не укажете . Затем вы должны получить ошибку, похожую на:
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]
причина этого заключается в том, что стандарт C++ не определяет, как должна быть реализована плавающая точка и оставлена на процессор. Чтобы обойти это и другие ограничения
constexpr
был введенный.
если он вам нужен только в одном методе, вы можете объявить его локально статическим:
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 ); } };
я столкнулся с реальными проблемами с этим, потому что мне нужен один и тот же код для компиляции с разными версиями g++ (компилятор GNU C++). Поэтому мне пришлось использовать макрос, чтобы увидеть, какая версия компилятора используется, а затем действовать соответственно, например
#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, но я подозреваю, что вы можете сделать то же самое с другими компиляторами.
Ну, не совсем прямой ответ, но какая-то конкретная причина не использовать макрос?
#define tolerance 0.001 struct equal_vec { bool operator() (const Vector3D& a, const Vector3D& b) const { Vector3D dist = b - a; return ( dist.length2() <= tolerance ); } };
не совсем хорошая практика C#, но ИМХО совершенно законно в C++.