【问题标题】:Scope quandary with namespaces, function templates, and static data名称空间、函数模板和静态数据的范围困境
【发布时间】: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


    【解决方案1】:

    如果只有函数模板的特化才能访问数据真的很重要,您可以使用具有静态成员的类来保存数据。

    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];
        // ...
    }
    

    【讨论】:

      猜你喜欢
      • 2012-04-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多