C ++, де ініціалізувати статичний const


129

У мене клас

class foo {
public:
   foo();
   foo( int );
private:
   static const string s;
};

Де найкраще місце для ініціалізації рядка sу вихідному файлі?

Відповіді:


178

В будь-якому місці одного блоку компіляції (як правило, .cpp-файл) буде зроблено:

foo.h

class foo {
    static const string s; // Can never be initialized here.
    static const char* cs; // Same with C strings.

    static const int i = 3; // Integral types can be initialized here (*)...
    static const int j; //     ... OR in cpp.
};

foo.cpp

#include "foo.h"
const string foo::s = "foo string";
const char* foo::cs = "foo C string";
// No definition for i. (*)
const int foo::j = 4;

(*) Відповідно до стандартів ви повинні визначитись iпоза визначенням класу (як jє), якщо воно використовується в коді, відмінному від просто інтегральних постійних виразів. Детальніше дивіться у коментарі Девіда нижче.


27
Я відмовив, але після перегляду стандарту у вашому коді є помилка: iмає бути визначено в cpp. § 9.4.2 / 4 Якщо статичний член даних має інтегральний тип const або перерахунок const, його оголошення у визначенні класу може визначати константа-ініціалізатор, яка має бути інтегральним постійним виразом (5.19). У цьому випадку член може з'являтися в цілісних постійних виразах. Член все ж повинен бути визначений в області простору імен, якщо він використовується в програмі, а визначення обсягу простору імен не повинно містити ініціалізатор.
Девід Родрігес - дрибес

3
Виходячи з вашої цитати зі стандартів, схоже i, її слід було б визначити лише в тому випадку, якщо вона буде використана деінде, ніж у цілісних постійних виразах, правда? У цьому випадку ви не можете сказати, що є помилка, оскільки недостатньо контексту для впевненості - або строго кажучи, що приклад вище є правильним, якщо іншого коду немає. Зараз я ціную ваш коментар (+1), я все ще сам вчусь! Тож я спробую уточнити цю точку у відповіді, будь ласка, дайте мені знати, чи краще ...
писати

@squelart Вибачте, якщо я звучу глупо, але прикладом твердження, відмінним від інтегрального постійного виразу, буде?
Сакшам

3
@Saksham Наприклад, виклик функції, наприклад: int f() { return 42; } class foo { static const int i = f(); /* Error! */ }Зауважте, що C ++ 11 дозволяє викликати функції "constexpr":constexpr int f() { return 42; } class foo { static const int i = f(); /* Ok */ }
squelart

@squelart Я прочитав текст таким чином, що визначення повинно бути надане, якщо член взагалі використовується - формулювання в стандарті не обмежує цю вимогу інтегральними постійними виразами.
ВладЛосєв

12

Статичні члени потрібно ініціалізувати в блоці перекладу .cpp в області файлу або у відповідному просторі імен:

const string foo::s( "my foo");

11

У підрозділі перекладу в одному просторі імен, як правило, вгорі:

// foo.h
struct foo
{
    static const std::string s;
};

// foo.cpp
const std::string foo::s = "thingadongdong"; // this is where it lives

// bar.h
namespace baz
{
    struct bar
    {
        static const float f;
    };
}

// bar.cpp
namespace baz
{
    const float bar::f = 3.1415926535;
}

8

Оскільки C ++ 17, вбудований специфікатор також застосовується до змінних. Тепер ви можете визначити статичні змінні члена у визначенні класу:

#include <string>

class foo {
public:
   foo();
   foo( int );
private:
   inline static const std::string s { "foo" };
};

1

static const int ARRAYSIZEУ файлі заголовка ініціалізуються лише цілісні значення (наприклад, ), оскільки вони зазвичай використовуються в заголовку класу, щоб визначити щось таке, як розмір масиву. Неінтегральні значення ініціалізуються у файлі реалізації.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.