【发布时间】:2009-04-23 08:35:13
【问题描述】:
我有一个静态类成员,它是一些容器,比如
(Foo.h)
class Foo
{
...
private:
static list<string> s_List;
}
我需要用一些特定值填充列表。实际上它也应该是 const,但这可能会使问题进一步复杂化。 所有的类成员函数都是静态的,所以在构造函数中初始化它没有意义。
【问题讨论】:
我有一个静态类成员,它是一些容器,比如
(Foo.h)
class Foo
{
...
private:
static list<string> s_List;
}
我需要用一些特定值填充列表。实际上它也应该是 const,但这可能会使问题进一步复杂化。 所有的类成员函数都是静态的,所以在构造函数中初始化它没有意义。
【问题讨论】:
一个常见的解决方案是这样做:
// 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());
另一种方法就像 Neil Butterworth 建议的那样。
【讨论】:
另一种选择是创建一个简单的初始化器类:
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 的朋友。将这些类包含在它们正在初始化的类中通常也很方便。
但是,我刚刚重新阅读了您的问题,然后又出现了另一个想法 - 如果列表是 const,您可能不会更改它,在这种情况下,使用按排序顺序初始化的字符串的简单数组可能是更好的解决方案。搜索(使用 std::binary_search)肯定会比列表更快,当然也可以很容易地初始化。
【讨论】:
如果你的编译器支持 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;
}
这适用于 const 和非 const 静态成员。我已经用 clang-4.2、gcc-4.7、gcc-4.6 和 gcc-4.5 测试了这个 sn-p。 Gcc-4.5 不支持更新的 for 语法,因此您必须使用带有迭代器的传统 for 循环。另外,不要忘记将 -std=c++0x 标志传递给编译器。我相当有信心 Visual Studio 也支持这一点,但我不确定也不知道哪些版本。
【讨论】:
这取决于您需要在该列表中放入哪些值。它们是静态的还是需要某种形式的计算?
如果它们是静态的,您可以这样做:
namespace {
const char* const initVals[] = { "A", "B", "C" };
}
list<string> Foo::s_list(initVals, initVals + 3);
【讨论】:
一种可能的解决方案是使用访问器方法来检查它是否已初始化,如果未初始化则执行此操作。
【讨论】:
我(问题的作者)尝试这样做的方法是徒劳的。
我试图做类似的事情(在 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()。但这很丑!
【讨论】: