这个作用域问题看起来像是C++中的一个难题,Scott Meyers可能在他的Effective C++书籍中解决了这个问题。
我有一个名为
我的第一个尝试是将表格放在
但是现在我有了多个表的副本,因为每个包含这个头文件的编译单元都有自己的表。如果
我有一个名为
Analyze
的函数,对一系列数据进行分析。该函数从几个不同类型的迭代器中调用,因此我将其制作成了一个模板(因此在头文件中实现)。该函数依赖于一个静态数据表AnalysisTable
,我不想将其暴露给其他代码。我的第一个尝试是将表格放在
Analysis
内部作为static const
。namespace MyNamespace {
template <typename InputIterator>
int Analyze(InputIterator begin, InputIterator end) {
static const int AnalysisTable[] = { /* data */ };
... // implementation uses AnalysisTable
return result;
}
} // namespace MyNamespace
看起来编译器会为每个Analyze
实例创建一个AnalysisTable
的副本,这样会浪费空间(并且在一定程度上浪费时间)。
因此,我将表格移到了函数外面,像这样:
namespace MyNamespace {
const int AnalysisTable[] = { /* data */ };
template <typename InputIterator>
int Analyze(InputIterator begin, InputIterator end) {
... // implementation uses AnalysisTable
return result;
}
} // namespace MyNamespace
现在只有一个表的副本,但它暴露给了代码的其他部分。我希望将这个实现细节隐藏起来,因此我引入了一个未命名的命名空间:
namespace MyNamespace {
namespace { // unnamed to hide AnalysisTable
const int AnalysisTable[] = { /* data */ };
} // unnamed namespace
template <typename InputIterator>
int Analyze(InputIterator begin, InputIterator end) {
... // implementation uses AnalysisTable
return result;
}
} // namespace MyNamespace
但是现在我有了多个表的副本,因为每个包含这个头文件的编译单元都有自己的表。如果
Analyze
不是一个模板,我可以将所有的实现细节移出头文件。但它是一个模板,所以我似乎无法做到这一点。我的下一步尝试是将表放在实现文件中,并在 Analyze
中进行 extern
声明。// foo.h ------
namespace MyNamespace {
template <typename InputIterator>
int Analyze(InputIterator begin, InputIterator end) {
extern const int AnalysisTable[];
... // implementation uses AnalysisTable
return result;
}
} // namespace MyNamespace
// foo.cpp ------
#include "foo.h"
namespace MyNamespace {
const int AnalysisTable[] = { /* data */ };
}
这看起来应该是可行的,编译器也没问题。然而,连接器报错:"无法解析的外部符号AnalysisTable
." 真糟糕!(有人能解释一下我错在哪里吗?)
我能想到的唯一办法就是给内部命名空间一个名称,在头文件中声明该表格,并在实现文件中提供实际数据:
// foo.h -----
namespace MyNamespace {
namespace PrivateStuff {
extern const int AnalysisTable[];
} // unnamed namespace
template <typename InputIterator>
int Analyze(InputIterator begin, InputIterator end) {
... // implementation uses PrivateStuff::AnalysisTable
return result;
}
} // namespace MyNamespace
// foo.cpp -----
#include "foo.h"
namespace MyNamespace {
namespace PrivateStuff {
const int AnalysisTable[] = { /* data */ };
}
}
再次强调,我只有一个AnalysisTable
实例(耶!),但程序的其他部分可以访问它(糟糕!)。内部命名空间使得它们不应该访问,但仍然有可能。
是否有可能只保留一张表的实例,并将其移动到除Analyze
之外的所有内容之外?