C++ static constant string (CLASS member)
Chciałbym mieć prywatną stałą statyczną dla klasy (w tym przypadku shape-factory). Chciałbym mieć coś takiego.
class A {
private:
static const string RECTANGLE = "rectangle";
}
Niestety dostaję różnego rodzaju błędy z kompilatora C++ (g++), takie jak:
ISO C++ zabrania inicjalizacji member 'RECTANGLE'
Nieprawidłowa inicjalizacja w klasie statycznego elementu danych nieintegralnego typu 'std:: string'
Error: making 'RECTANGLE' static
To mi mówi, że tego rodzaju konstrukcja prętów nie jest zgodna ze standardem. Jak można mieć prywatną stałą literalną (a może publiczną) bez konieczności używania dyrektywy #define (chcę uniknąć brzydoty globalności danych!)
Każda pomoc jest mile widziana. Dzięki.11 answers
Musisz zdefiniować swojego statycznego członka poza definicją klasy i podać tam inicjalizator.
Pierwszy
// In a header file (if it is in a header file in your case)
class A {
private:
static const string RECTANGLE;
};
A następnie
// In one of the implementation files
const string A::RECTANGLE = "rectangle";
Składnia, której pierwotnie próbowałeś użyć (inicjalizacja wewnątrz definicji klasy) jest dozwolona tylko dla typów integral i enum.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-02 06:30:06
W C++11 możesz zrobić teraz:
class A {
private:
static constexpr const char* STRING = "some useful string constant";
};
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-21 11:27:54
Wewnątrz definicji klas można tylko zadeklarować statyczne elementy. Muszą być zdefiniowane poza klasą. Dla stałych całkowych w czasie kompilacji standard czyni wyjątek, że można "inicjalizować" elementy składowe. To wciąż nie jest definicja. Przyjęcie adresu nie zadziałałoby na przykład bez definicji.
Chciałbym wspomnieć, że nie widzę korzyści z używania std:: string over const char [] dla stałych . std:: string is nice and all but wymaga dynamicznej inicjalizacji. Więc jeśli napiszesz coś w stylu
const std::string foo = "hello";
W obszarze przestrzeni nazw konstruktor foo zostanie uruchomiony tuż przed uruchomieniem main i ten konstruktor utworzy kopię stałej "hello" w pamięci sterty. Chyba, że naprawdę potrzebujesz RECTANGLE aby być std:: string możesz równie dobrze napisać
// 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";
Tam! Bez alokacji sterty, bez kopiowania, bez dynamicznej inicjalizacji.
Pozdrawiam, s.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-14 08:30:25
To tylko dodatkowe informacje, ale jeśli naprawdę chcesz, aby ciąg był w pliku nagłówkowym, spróbuj czegoś takiego:
class foo
{
public:
static const std::string& RECTANGLE(void)
{
static const std::string str = "rectangle";
return str;
}
};
Chociaż wątpię, żeby to było zalecane.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-14 02:08:58
Aby użyć inicjalizacji w klasie składni, stała musi być statyczna const typu całkowego lub wyliczeniowego inicjowane wyrażeniem stałym.
To jest ograniczenie. Dlatego w tym przypadku musisz zdefiniować zmienną poza klasą. odsyłacz od @ AndreyT
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-14 02:07:11
W C++ 17 możesz użyć zmiennych inline :
class A {
private:
static inline const std::string my_string = "some useful string constant";
};
Zauważ, że to różni się od otchłani.Odpowiedź 7 : ta definiuje rzeczywisty std::string
obiekt, a nie const char*
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-02 15:15:39
Bieżący standard pozwala na taką inicjalizację tylko dla statycznych stałych typów całkowych. Więc musisz zrobić to, co wyjaśnił AndreyT. Jednak będzie to dostępne w następnym standardzie poprzez składnię inicjalizacji new member .
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-14 02:11:01
Possible just do:
static const std::string RECTANGLE() const {
return "rectangle";
}
Lub
#define RECTANGLE "rectangle"
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-09 09:49:04
Możesz wybrać rozwiązanie const char*
wymienione powyżej, ale jeśli potrzebujesz ciągów przez cały czas, będziesz miał dużo kosztów.
Z drugiej strony, statyczny ciąg znaków wymaga dynamicznej inicjalizacji, więc jeśli chcesz użyć jego wartości podczas inicjalizacji innej zmiennej globalnej / statycznej, możesz napotkać problem kolejności inicjalizacji. Aby tego uniknąć, najtańszą rzeczą jest dostęp do statycznego obiektu string poprzez getter, który sprawdza, czy obiekt jest zainicjowany, czy nie.
//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;
}
Pamiętaj, aby używać tylko A::getS()
. Ponieważ wątek może być uruchamiany tylko przez main()
, a A_s_initialized
jest inicjowany przed main()
, nie potrzebujesz blokad nawet w środowisku wielowątkowym. A_s_initialized
domyślnie wynosi 0 (przed dynamiczną inicjalizacją), więc jeśli użyjesz getS()
przed inicjalizacją s, wywołasz funkcję init bezpiecznie.
Btw, w odpowiedzi powyżej: "static const std:: string RECTANGLE () const ", funkcje statyczne nie mogą być const
, ponieważ nie mogą zmienić stan, jeśli jakikolwiek obiekt i tak (nie ma tego wskaźnika).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-23 11:45:32
Zmienne statyczne klasy mogą być zadeklarowane w nagłówku, ale muszą być zdefiniowane W A .plik cpp. Dzieje się tak dlatego, że może być tylko jedna instancja zmiennej statycznej i kompilator nie może zdecydować, w którym wygenerowanym pliku obiektowym ją umieścić, więc musisz podjąć decyzję, zamiast tego.
Aby zachować definicję wartości statycznej z deklaracją w C++11 można użyć zagnieżdżonej statycznej struktury. W tym przypadku element statyczny jest strukturą i musi być zdefiniowane w a .plik cpp, ale wartości są w nagłówku.
class A
{
private:
static struct _Shapes {
const std::string RECTANGLE {"rectangle"};
const std::string CIRCLE {"circle"};
} shape;
};
Zamiast inicjalizacji poszczególnych członów inicjalizowana jest cała statyczna struktura .cpp:
A::_Shapes A::shape;
Wartości są dostępne za pomocą
A::shape.RECTANGLE;
Or -- since the members are private and are mean to be used only from a -- with
shape.RECTANGLE;
Zauważ, że to rozwiązanie nadal cierpi na problem kolejności inicjalizacja zmiennych statycznych. Gdy wartość statyczna jest używana do initialize inną zmienną statyczną, pierwsza może nie być zainicjalizowana, jeszcze.
// 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<std::string> headers{ File::extension.h, File::extension.hpp };
W tym przypadku zmienna statyczna nagłówki będzie zawierać albo { "" } lub { ".h",".hpp"}, w zależności od kolejności inicjalizacji utworzonej przez linkera.
Jak wspomniano przez @ abyss.7 Możesz również użyć constexpr
, Jeśli wartość zmiennej może być obliczona w czasie kompilacji. Ale jeśli zadeklarujesz swoje ciągi za pomocą static constexpr const char*
i twój program użyje std::string
w przeciwnym razie będzie overhead, ponieważ nowy std::string
obiekt będzie tworzony za każdym razem, gdy użyjesz takiej stałej:
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.
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-19 09:05:36
Przewiń do przodu do 2018 I 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_ ;
}
};
Powyżej jest odpowiedni i legalny standard C++ citizen. Może łatwo zaangażować się w dowolne algorytmy std::, kontenery, narzędzia itp. Na przykład:
// 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"
);
Enjoy the standard C++
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-20 18:42:04