命名空间、函数模板和静态数据的作用域问题

3
这个作用域问题看起来像是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之外的所有内容之外?

1个回答

3
如果非常重要的话,您可以使用一个具有静态成员的类来保存数据,以便只有您的函数模板的特化才能访问该数据。
class AnalysisTable
{
    static const int data[];

    template <typename InputIterator>
    friend int Analyze(InputIterator begin, InputIterator end);
};

template <typename InputIterator>
int Analyze(InputIterator begin, InputIterator end)
{
    // ...
    x = AnalysisTable::data[n];
    // ...
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接