Статическая константная строка C ++ (член classа)

Я бы хотел иметь частную статическую константу для classа (в данном случае фабрику форм). Я бы хотел кое-что сделать.

class A { private: static const string RECTANGLE = "rectangle"; } 

К сожалению, я получаю всевозможные ошибки от компилятора C ++ (g ++), например:

ISO C ++ запрещает инициализацию элемента «RECTANGLE»

недействительная инициализация classа в статическом элементе данных нецелого типа ‘std :: string’

Ошибка: создание статического значения RECTANGLE

Это говорит о том, что такой дизайн-член не соответствует стандарту. Как у вас есть личная константа литерала (или, возможно, общедоступная), без использования директивы #define (я хочу избежать уродства глобальной целостности данных!)

Любая помощь приветствуется. Благодарю.

Вы должны определить свой статический член вне определения classа и предоставить там инициализатор.

Первый

 // In a header file (if it is in a header file in your case) class A { private: static const string RECTANGLE; }; 

а потом

 // In one of the implementation files const string A::RECTANGLE = "rectangle"; 

Синтаксис, который вы изначально пытались использовать (инициализатор внутри определения classа), разрешен только с интегральными и перечисляемыми типами.

В C ++ 11 вы можете сделать это сейчас:

 class A { private: static constexpr const char* STRING = "some useful string constant"; }; 

В определениях внутри classа вы можете объявлять только статические члены. Они должны быть определены вне classа. Для интегральных констант времени компиляции стандарт делает исключение, которое вы можете «инициализировать». Однако это еще не определение. Например, адрес не будет работать без определения.

Я хотел бы упомянуть, что я не вижу преимущества использования std :: string над const char [] для констант . std :: string хорош, и все это требует динамической инициализации. Итак, если вы пишете что-то вроде

 const std::string foo = "hello"; 

в области пространства имен конструктор foo будет запускаться непосредственно перед выполнением основных запусков, и этот конструктор создаст копию константы «hello» в памяти кучи. Если вам действительно не нужно, чтобы RECTANGLE был std :: string, вы могли бы просто написать

 // class definition with incomplete static member could be in a header file class A { static const char RECTANGLE[]; }; // this needs to be placed in a single translation unit only const char A::RECTANGLE[] = "rectangle"; 

Там! Отсутствие выделения кучи, отсутствие копирования, отсутствие динамической инициализации.

Привет, с.

Это просто дополнительная информация, но если вы действительно хотите строку в файле заголовка, попробуйте что-то вроде:

 class foo { public: static const std::string& RECTANGLE(void) { static const std::string str = "rectangle"; return str; } }; 

Хотя я сомневаюсь, что это рекомендуется.

Чтобы использовать этот синтаксис инициализации в classе, константа должна быть статической константой интегрального или перечисляемого типа, инициализированной константным выражением.

Это ограничение. Следовательно, в этом случае вам нужно определить переменную вне classа. ответьте на сообщение от @AndreyT

В C ++ 17 вы можете использовать встроенные переменные :

 class A { private: static inline const std::string my_string = "some useful string constant"; }; 

Обратите внимание, что это отличается от ответа abyss.7 : этот определяет фактический объект std::string , а не const char*

Текущий стандарт допускает такую ​​инициализацию для статических постоянных интегральных типов. Поэтому вам нужно сделать, как объяснил AndreyT. Однако это будет доступно в следующем стандарте через новый синтаксис инициализации члена .

возможно только сделать:

 static const std::string RECTANGLE() const { return "rectangle"; } 

или

 #define RECTANGLE "rectangle" 

Вы можете либо пойти для решения const char* упомянутого выше, но тогда, если вам нужна строка все время, у вас будет много накладных расходов.
С другой стороны, статическая строка нуждается в динамической инициализации, поэтому, если вы хотите использовать ее значение во время другой инициализации глобальной / статической переменной, вы можете столкнуться с проблемой порядка инициализации. Чтобы этого избежать, самым дешевым является доступ к статическому объекту string через getter, который проверяет, инициализирован ли ваш объект или нет.

 //in a header class A{ static string s; public: static string getS(); }; //in implementation string A::s; namespace{ bool init_A_s(){ A::s = string("foo"); return true; } bool A_s_initialized = init_A_s(); } string A::getS(){ if (!A_s_initialized) A_s_initialized = init_A_s(); return s; } Пространство //in a header class A{ static string s; public: static string getS(); }; //in implementation string A::s; namespace{ bool init_A_s(){ A::s = string("foo"); return true; } bool A_s_initialized = init_A_s(); } string A::getS(){ if (!A_s_initialized) A_s_initialized = init_A_s(); return s; } 

Не забудьте использовать только A::getS() . Поскольку любая A_s_initialized может запускаться только main() , а A_s_initialized инициализируется до main() , вам не нужны блокировки даже в многопоточной среде. A_s_initialized равен 0 по умолчанию (перед динамической инициализацией), поэтому, если вы используете getS() до инициализации s, вы вызываете функцию init безопасно.

Btw, в ответе выше: « static const std :: string RECTANGLE () const », статические функции не могут быть const потому что они не могут изменять состояние, если какой-либо объект в любом случае (этот указатель отсутствует).

Статические переменные classа могут быть объявлены в заголовке, но должны быть определены в файле .cpp. Это связано с тем, что может быть только один экземпляр статической переменной, и компилятор не может решить, в какой сгенерированный объектный файл поставить его, чтобы вы приняли решение.

Чтобы сохранить определение статического значения с помощью объявления в C ++ 11, можно использовать вложенную статическую структуру. В этом случае статический член является структурой и должен быть определен в .cpp-файле, но значения находятся в заголовке.

 class A { private: static struct _Shapes { const std::string RECTANGLE {"rectangle"}; const std::string CIRCLE {"circle"}; } shape; }; 

Вместо инициализации отдельных элементов вся статическая структура инициализируется в .cpp:

 A::_Shapes A::shape; 

Доступ к значениям осуществляется с помощью

 A::shape.RECTANGLE; 

или – поскольку члены являются частными и предназначены для использования только с A – с

 shape.RECTANGLE; 

Обратите внимание, что это решение все еще страдает от проблемы порядка инициализации статических переменных. Когда статическое значение используется для инициализации другой статической переменной, первая может еще не инициализироваться.

 // file.h class File { public: static struct _Extensions { const std::string h{ ".h" }; const std::string hpp{ ".hpp" }; const std::string c{ ".c" }; const std::string cpp{ ".cpp" }; } extension; }; // file.cpp File::_Extensions File::extension; // module.cpp static std::set headers{ File::extension.h, File::extension.hpp }; 

В этом случае статические заголовки переменных будут содержать либо {“”}, либо {“.h”, “.pp”}, в зависимости от порядка инициализации, созданного компоновщиком.

Как упоминалось в @ abyss.7, вы также можете использовать constexpr если значение переменной можно вычислить во время компиляции. Но если вы объявляете свои строки со static constexpr const char* и ваша программа использует std::string противном случае будут накладные расходы, потому что при каждом использовании такой константы будет создан новый объект std::string :

 class A { public: static constexpr const char* STRING = "some value"; }; void foo(const std::string& bar); int main() { foo(A::STRING); // a new std::string is constructed and destroyed. } 

Быстрая перемотка вперед до 2018 и C ++ 17.

 using namespace std::literals; namespace STANDARD { constexpr inline auto compiletime_static_string_view_constant() { // make and return string view literal // will stay the same for the whole application lifetime // will exhibit standard and expected interface // will be usable at both // runtime and compile time // by value semantics implemented for you auto made_once_when_needed_ = "compile time"sv; return made_once_when_needed_ ; } }; 

Выше – нормальный гражданский гражданин C ++. Он может легко включаться в любые и все std :: алгоритмы, контейнеры, утилиты и тому подобное. Например:

 // test the resilience auto return_by_val = []() { auto return_by_val = []() { auto return_by_val = []() { auto return_by_val = []() { return STANDARD::compiletime_static_string_view_constant(); }; return return_by_val(); }; return return_by_val(); }; return return_by_val(); }; // actually a run time _ASSERTE(return_by_val() == "compile time"); // compile time static_assert( STANDARD::compiletime_static_string_view_constant() == "compile time" ); 

Наслаждайтесь стандартным C ++

  • Java Замена нескольких разных подстрок в строке сразу (или наиболее эффективным способом)
  • Преобразование строки в целое число на Android
  • В чем разница между строкой и строкой в ​​C #?
  • Как получить двойные кавычки в строковый литерал?
  • Вставьте символ в строку в определенном месте
  • Как взорвать вектор строк в строку (элегантный способ)
  • Разница между пустой и пустой ("") строкой Java
  • Использование конструктора String (String) в Java
  • Удалите часть строки после "."
  • Как избавиться от `устаревшего преобразования из строковой константы в 'char *' 'предупреждения в GCC?
  • Как я могу разбирать строку в BigDecimal?
  • Давайте будем гением компьютера.