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

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 был введенный.

да. Просто добавьте 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++.