Я хотел бы иметь частную статическую константу для класса (в данном случае фабрика форм).
Я хотел бы иметь что-то в этом роде.
class A {
private:
static const string RECTANGLE = "rectangle";
}
К сожалению, я получаю всевозможные ошибки от компилятора C ++ (g ++), такие как:
ISO C ++ запрещает инициализацию члена 'RECTANGLE'
недопустимая инициализация в классе статического члена данных нецелого типа 'std :: string'
ошибка: сделать статический RECTANGLE
Это говорит мне о том, что подобный дизайн элементов не соответствует стандарту. Как у вас есть личная литеральная константа (или, возможно, общедоступная) без необходимости использования директивы #define (я хочу избежать уродливости глобальности данных!)
Любая помощь приветствуется.
Ответы:
Вы должны определить свой статический член вне определения класса и предоставить там инициализатор.
Первый
а потом
Синтаксис, который вы изначально пытались использовать (инициализатор внутри определения класса), разрешен только для целочисленных и перечислимых типов.
Начиная с C ++ 17 у вас есть другая опция, которая очень похожа на ваше первоначальное объявление: встроенные переменные
Никакого дополнительного определения не требуется.
Или вместо этого
const
вы можете объявить этоconstexpr
в этом варианте. Явноеinline
больше не нужно, посколькуconstexpr
подразумеваетinline
.источник
char const*
есть добро , что она инициализируется перед всеми инициализации динамической делается. Таким образом, в конструкторе любого объекта вы можете положиться на то,RECTANGLE
что он уже был инициализирован.В C ++ 11 вы можете сделать сейчас:
источник
constexpr
подразумеваетconst
для вар, а не для типа он указывает. Т.е.static constexpr const char* const
такой же, какstatic constexpr const char*
, но не такой, какstatic constexpr char*
.Внутри определений классов вы можете объявлять только статические члены. Они должны быть определены вне класса. Для интегральных констант времени компиляции стандарт делает исключение, что вы можете «инициализировать» элементы. Это все еще не определение, хотя. Взятие адреса не будет работать без определения, например.
Я хотел бы отметить, что я не вижу преимущества использования std :: string перед const char [] для констант . std :: string хорош и все, но требует динамической инициализации. Итак, если вы напишите что-то вроде
в области имен пространства конструктор foo будет запущен непосредственно перед выполнением основных запусков, и этот конструктор создаст копию постоянной «hello» в памяти кучи. Если вам действительно не нужен RECTANGLE, чтобы быть std :: string, вы можете написать
Там! Нет выделения кучи, нет копирования, нет динамической инициализации.
Ура, с.
источник
Это просто дополнительная информация, но если вам действительно нужна строка в заголовочном файле, попробуйте что-то вроде:
Хотя я сомневаюсь, что это рекомендуется.
источник
В C ++ 17 вы можете использовать встроенные переменные :
Обратите внимание, что это отличается от ответа abyss.7 : этот определяет реальный
std::string
объект, а неconst char*
источник
inline
создаст много дубликатов?Это ограничение. Следовательно, в этом случае вам нужно определить переменную вне класса. см. ответ от @AndreyT
источник
Статические переменные класса могут быть объявлены в заголовке, но должны быть определены в файле .cpp. Это связано с тем, что может быть только один экземпляр статической переменной, и компилятор не может решить, в какой сгенерированный объектный файл поместить его, поэтому вам придется принять решение.
Чтобы сохранить определение статического значения с объявлением в C ++ 11, можно использовать вложенную статическую структуру. В этом случае статический член является структурой и должен быть определен в файле .cpp, но значения находятся в заголовке.
Вместо инициализации отдельных элементов вся статическая структура инициализируется в .cpp:
Доступ к значениям
или - поскольку члены являются частными и предназначены для использования только из А - с
Обратите внимание, что это решение все еще страдает от проблемы порядка инициализации статических переменных. Когда статическое значение используется для инициализации другой статической переменной, первая может еще не инициализироваться.
В этом случае заголовки статических переменных будут содержать либо {""}, либо {".h", ".hpp"}, в зависимости от порядка инициализации, созданного компоновщиком.
Как уже упоминалось @ abyss.7, вы также можете использовать,
constexpr
если значение переменной может быть вычислено во время компиляции. Но если вы объявите свои строки с помощьюstatic constexpr const char*
и ваша программа будет использоватьstd::string
иначе, это приведет к дополнительным издержкам, потому что новыйstd::string
объект будет создаваться каждый раз, когда вы используете такую константу:источник
Текущий стандарт допускает такую инициализацию только для статических постоянных целочисленных типов. Так что вам нужно сделать, как объяснил AndreyT. Однако это будет доступно в следующем стандарте через новый синтаксис инициализации члена .
источник
можно просто сделать:
или
источник
constexpr
но вы не можете создать статическую функциюconst
.static const std::string RECTANGLE() const { static const std::string value("rectangle"); return value; }
Вы можете выбрать
const char*
решение, упомянутое выше, но тогда, если вам все время нужна строка, у вас будет много накладных расходов.С другой стороны, статическая строка требует динамической инициализации, поэтому, если вы хотите использовать ее значение во время инициализации другой глобальной / статической переменной, вы можете столкнуться с проблемой порядка инициализации. Чтобы избежать этого, самый дешевый способ - получить доступ к статическому строковому объекту через геттер, который проверяет, инициализирован ли ваш объект или нет.
Не забудьте использовать только
A::getS()
. Поскольку любой поток может быть запущен толькоmain()
иA_s_initialized
инициализирован раньшеmain()
, вам не нужны блокировки даже в многопоточной среде.A_s_initialized
по умолчанию 0 (до динамической инициализации), поэтому, если вы используетеgetS()
до инициализации s, вы вызываете функцию init безопасно.Кстати, в ответе выше: « static const std :: string RECTANGLE () const », статические функции не могут быть,
const
потому что они не могут изменить состояние, если какой-либо объект в любом случае (этот указатель отсутствует).источник
Перенесемся в 2018 и C ++ 17.
static_assert 'работает' только во время компиляции
};
Выше - надлежащий и юридический стандарт гражданина C ++. Он может легко включиться в любые алгоритмы std ::, контейнеры, утилиты и тому подобное. Например:
Наслаждайтесь стандартом C ++
источник
std::string_view
для констант, только если вы используетеstring_view
параметры во всех ваших функциях. Если какая-либо из ваших функций используетconst std::string&
параметр, при передачеstring_view
константы через этот параметр будет создана копия строки . Если ваши константы имеют тип,std::string
копии не будут созданы ни дляconst std::string&
параметров, ни дляstd::string_view
параметров.inline
переменные появились в C ++ 17 с их семантикой ODR. Но string_view тоже C ++ 17, так что простоconstexpr auto some_str = "compile time"sv;
выполняет работу (и на самом деле, это не переменная, аconstexpr
, значитinline
, неявная; если у вас есть переменная - то есть, нетconstexpr
- тогда этоinline auto some_str = "compile time"sv;
будет сделано, хотя, конечно, область имен пространства имен переменная, которая по сути является глобальной переменной, редко будет хорошей идеей).