【发布时间】:2011-02-14 15:26:41
【问题描述】:
这个范围界定问题似乎是 Scott Meyers 在他的一本Effective C++书籍中解决的 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 之外的任何地方?
【问题讨论】:
标签: c++ templates namespaces scope