Заполните контейнер статического члена в C ++ - PullRequest
11 голосов
/ 23 апреля 2009

У меня есть статический член класса, который является каким-то контейнером, например

(foo.h)

class Foo
{
   ...
private:
   static list<string> s_List;
}

Мне нужно заполнить список рядом определенных значений. На самом деле это также должно быть const , но это может еще больше усложнить проблему. Все функции-члены класса являются статическими, поэтому инициализация их в конструкторе не имеет смысла.

Ответы [ 6 ]

15 голосов
/ 23 апреля 2009

общее решение - сделать что-то вроде этого:

// 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());

другой метод похож на предложенный Нилом Баттервортом.

8 голосов
/ 23 апреля 2009

Другой альтернативой является создание простого класса инициализатора:

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;

Обратите внимание, что, поскольку список является закрытым, это, вероятно, потребует от вас сделать Init другом Foo. Также часто бывает удобно, чтобы такие классы содержались в классе, который они инициализируют.

Однако я просто перечитал ваш вопрос и возникла другая мысль - если список постоянный, вы, вероятно, не будете его изменять, и в этом случае простой массив строк, инициализированный со строками в отсортированном порядке, может лучшее решение. Конечно, поиск будет быстрее (с использованием std :: binary_search), чем в списке, и, конечно, его легко инициализировать.

4 голосов
/ 07 мая 2013

Если ваш компилятор поддерживает C ++ 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 = c ++ 0x . Я достаточно уверен, что Visual Studio также поддерживает это, но я точно не знаю и не знаю, какие версии.

1 голос
/ 23 апреля 2009

Это зависит от того, какие значения вы должны поместить в этот список. Они статичны или требуют какой-то формы вычислений?

Если они статичны, вы можете сделать это:

namespace {
   const char* const initVals[] = { "A", "B", "C" };
}

list<string> Foo::s_list(initVals, initVals + 3);
0 голосов
/ 23 апреля 2009

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

0 голосов
/ 23 апреля 2009

Способы, которыми я (автор вопроса) тщетно пытался это сделать.


Я пытался сделать что-то вроде (в 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 (). Но это безобразно!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...