Пространство области действия с пространствами имен, шаблонами функций и статическими данными - PullRequest
3 голосов
/ 02 мая 2010

Эта проблема с областями видимости напоминает проблему С ++, о которой Скотт Мейерс мог бы рассказать в одной из своих Эффективных С ++ книг.

У меня есть функция Analyze, которая выполняет некоторый анализ диапазона данных. Функция вызывается из нескольких мест с различными типами итераторов, поэтому я сделал ее шаблоном (и таким образом реализовал его в заголовочном файле). Функция зависит от статической таблицы данных AnalysisTable, которую я не хочу показывать остальной части кода.

Мой первый подход состоял в том, чтобы сделать таблицу static const внутри Analysis.

namespace MyNamespace {

  template <typename InputIterator>
  int Analyze(InputIterator begin, InputIterator end) {
    static const int AnalysisTable[] = { /* data */ };
    ... // implementation uses AnalysisTable
    return result;
  }

}  // namespace MyNamespace

Похоже, что компилятор создает копию AnalysisTable для каждого экземпляра Analyze, что приводит к расточительству пространства (и, в небольшой степени, времени).

Поэтому я переместил таблицу за пределы функции следующим образом:

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 не был шаблоном, я мог бы переместить все детали реализации из файла заголовка. Но это шаблон, поэтому я, кажется, застрял.

Моей следующей попыткой было поместить таблицу в файл реализации и сделать объявление extern в Analyze.

// 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 голосов
/ 02 мая 2010

Вы можете использовать класс со статическим членом для хранения данных, если действительно важно, чтобы ничто, кроме специализаций вашего шаблона функции, не могло получить доступ к данным.

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];
    // ...
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...