Инициализация константного члена в объявлении класса в C ++ - PullRequest
70 голосов
/ 04 февраля 2012

В 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 или нет.

Ответы [ 5 ]

118 голосов
/ 09 февраля 2012

В C ++ 11, не 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, чтобы разрешить инициализатор в определении класса.

До C ++ 11 только static const члены данных целочисленного типа или типа перечисления могли иметь инициализаторы в определении класса.

43 голосов
/ 08 февраля 2012

Инициализация статических переменных-членов, отличных от типов const int, не является стандартом C ++ до C ++ 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]

Причина этого заключается в том, что стандарт C ++ не определяет, как должна быть реализована плавающая точка, и остается на усмотрение процессора.Чтобы обойти это и другие ограничения, введено constexpr.

11 голосов
/ 04 февраля 2012

Да. Просто добавьте ключевое слово constexpr, как говорит ошибка

1 голос
/ 27 октября 2016

Я столкнулся с реальными проблемами из-за этого, потому что мне нужен один и тот же код для компиляции с разными версиями 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, но я подозреваю, что вы можете сделать то же самое с другими компиляторами.

1 голос
/ 15 февраля 2012

Если вам нужен только один метод, вы можете объявить его локально статическим:

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 );
    }
};
...