Заполнение статического контейнера-члена в С++
У меня есть статический член класса, который представляет собой некоторый контейнер, например
(foo.h)
class Foo
{
...
private:
static list<string> s_List;
}
Мне нужно заполнить список несколькими конкретными значениями. На самом деле это должно быть также const, но это может еще больше усложнить проблему.
Все функции класса являются статическими, поэтому инициализация в конструкторе не имеет смысла.
Ответы
Ответ 1
общее решение состоит в том, чтобы сделать что-то вроде этого:
// header
class Foo
{
...
private:
static list<string> s_List;
}
// cpp
list<string> init()
{
list<string> tmp;
... fill tmp with strings
return tmp;
}
list<string> Foo::s_List(init());
другой метод похож на предложенный Нилом Баттерворт.
Ответ 2
Другой альтернативой является создание простого класса инициализации:
list <string> Foo::s_List;
struct Init {
Init() {
Foo::s_List.insert("apple");
Foo::s_List.insert("bannana");
Foo::s_List.insert("grapes");
}
};
static Init doInit;
Обратите внимание, что, поскольку список является закрытым, это, вероятно, потребует от вас инициировать друга Foo. Также часто бывает удобно, чтобы такие классы содержались в классе, который они инициализируют.
Однако я просто перечитываю ваш вопрос, и возникает другая мысль - если список const, вы, вероятно, не будете его менять, и в этом случае простой массив строк, инициализированный строками в отсортированном порядке, может быть лучшее решение. Конечно, быстрее искать (используя std:: binary_search), чем список, и, конечно же, легко инициализировать.
Ответ 3
Если ваш компилятор поддерживает С++ 0x, это фактически тривиально для выполнения.
#include <iostream>
#include <list>
class Foo
{
public:
static std::list<std::string> s_List;
};
std::list<std::string> Foo::s_List = {"hello", "world", "asdf", "qwerty"};
int main()
{
for(const std::string& str : Foo::s_List)
std::cout << str << std::endl;
return 0;
}
Это работает как для константных, так и для нестационарных статических членов. Я тестировал этот фрагмент с clang-4.2, gcc-4.7, gcc-4.6 и gcc-4.5. Gcc-4.5 не поддерживает обновленный синтаксис для, поэтому вам придется использовать традиционный цикл для с итераторами. Кроме того, не забудьте передать в компилятор флаг -std = С++ 0x. Я уверенно уверен, что Visual Studio поддерживает это, но я не знаю точно и не знаю, какие версии.
Ответ 4
Это зависит от того, какие значения нужно внести в этот список. Статичны они или требуют какой-либо формы вычислений?
Если они статичны, вы можете сделать это:
namespace {
const char* const initVals[] = { "A", "B", "C" };
}
list<string> Foo::s_list(initVals, initVals + 3);
Ответ 5
Пути, которые я (автор вопроса) тщетно пытались сделать это.
Я попытался сделать что-то вроде (в Foo.cpp):
list<string> Foo::s_List = list<string>();
Foo::s_List.insert("apple");
Foo::s_List.insert("bannana");
Foo::s_List.insert("grapes");
Но это дает ошибку компилятора.
Затем я подумал о том, чтобы сделать метод Initialize() и вызвать его прямо из кода
void Foo::Initialize()
{
s_List.insert("rats");
s_List.insert("cats");
}
Foo::Initialize();
//ошибка: компилятор считает, что это переопределение метода, а не вызов.
Единственная жизнеспособная идея, оставшаяся (еще не проверенная), должна была проверить, пуст ли пул в каждом методе, который его использует, и если это так, вызовите Initialize(). Но это уродливо!
Ответ 6
одним из возможных решений было бы использовать метод доступа, который проверяет, инициализирован ли он, и делает это, если это не так.