Что делать, если мне нужно анонимное пространство имен в заголовке?

В C++ анонимное пространство имен эквивалентно:

namespace $$$$ {
  //something
}
using namespace $$$$;

Где $$$$ — это какой-то уникальный идентификатор. Затем анонимное пространство имен полезно для кода, который не должен быть виден за пределами модуля компиляции.

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

Тогда вопрос в том, каков предлагаемый способ в этом случае? Я начал использовать именованное пространство имен под названием Private. На самом деле это не останавливает тех, кто хочет использовать внутренние идентификаторы, но, по крайней мере, уменьшает конфликты имен с идентификатором «Private».

Есть ли лучшие способы? Предложения?


person Paolo.Bolzoni    schedule 30.09.2014    source источник
comment
Насколько я знаю, это все, что вы можете сделать, библиотеки шаблонов часто используют пространства имен, такие как detail, именно для этой цели.   -  person user657267    schedule 30.09.2014
comment
В идеале весь ваш код должен находиться в каком-то пространстве имен. Поместите свои шаблоны в какое-то пространство имен под названием Utility, Alpha, MyWork или что-то в этом роде. И поместите туда функции помощи.   -  person Neil Kirk    schedule 30.09.2014
comment
Спасибо пользователю 657267; это было подтверждение, которое я искал. Я боялся, что упустил очевидное.   -  person Paolo.Bolzoni    schedule 30.09.2014


Ответы (3)


Придерживайтесь своего Private namespace (или используйте более популярный detail). Помните, что основная идея механизмов доступа C++ состоит в том, чтобы затруднить их неправильное использование, а не сделать невозможным. Защитите себя от несчастных случаев, а не от злонамеренных атак.

person Paul Evans    schedule 30.09.2014

Если вы отчаянно нуждаетесь в этой изоляции, почему бы не использовать старый добрый файл-static? Это не было рекомендовано:

template <typename T>
static void foo()
{}

int main()
{
    foo<char>();
}

Опять же, если вам нужно только foo в одной единице перевода, то, по-видимому, вы включаете его только в заголовок в этой единице перевода, и тогда не имеет никакого значения, находится ли он «в заголовке». Итак, просто не включайте шаблоны в другие единицы перевода, и вы уже в значительной степени достигли своей цели изоляции.

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

person Lightness Races in Orbit    schedule 30.09.2014
comment
+1: Шаблоны должны быть только в заголовке, если вы хотите использовать их в нескольких TU. - person Björn Pollex; 30.09.2014

Наиболее распространенный способ скрыть реализацию кода шаблона в заголовке — поместить реализацию в пространство имен с именем detail.

Например:

namespace cpputil { // my c++ utility library namespace

  namespace detail { // implementation details of this libraries headers go here

    // a functor private to the library
    template<class T>
    struct private_functor {
      private_functor(const T& t) : _t(t) {}
      void write(std::ostream& os) const { _t.write(os); }
    private:
      const T& _t;
    };

    // an extension to std::ostream::operator<<
    template<class T>
    std::ostream& operator<<(std::ostream& os, const private_functor<T>& pf)
    {
      pf.write(os);
      return os;
    }
  }

  /// a public template function that is designed to allow an object to be emitted to a stream
  /// returns a function object that calls T::write(std::ostream&) when placed into an
  /// output stream
  template<class T>
  detail::private_functor emit(const T& t) {
    return detail::private_functor<T>(t);
  }
}

// can be used like this:

int main() {
  struct S {
    void write(std::ostream& os) const { os << "{I am an S}"; }
  };

  std::cout << cpputil::emit(S) << std::endl;
  return 0;
}
person Richard Hodges    schedule 30.09.2014