Подтвердить что ты не робот

Инициализация члена 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 или нет.

4b9b3361

Ответ 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 совершенно законна в С++.