Извлечение кода пространства деталей из поля зрения - элегантно - PullRequest
2 голосов
/ 01 апреля 2020

Предположим, я пишу библиотеку только для заголовков или в основном для заголовков и имею следующий код:

using my_type = int;

namespace detail {
    inline void foo() { my_type x; do_foo_stuff(x); }
}

inline void bar() { do_bar_stuff(); detail::foo(); }
inline void baz(my_type y) { do_baz_stuff(y); detail::foo(); }

Я хочу поместить foo() в другой файл. Мотивация заключается в том, что у меня есть много таких детальных и не детализированных функций, и я хочу, чтобы заголовок с моим publi c API не был загроможден тем, что появляется внутри detail, и не предназначен для прямого использовать.

Вопрос в том, что за идиоматический c способ сделать это?

  • Я не могу просто включить файл с кодом detail:: в end моего заголовка publi c - поскольку объявления должны быть сделаны к тому времени, когда они используются.

  • Я не могу просто включить файл с кодом detail:: в начало моего заголовка publi c - поскольку они основаны на некоторых определениях publi c, например, типах и константах. Давайте предположим, что они не зависят от каких-либо функций .

Так что это не может быть одним из этих двух вариантов.

Ответы [ 2 ]

1 голос
/ 01 апреля 2020

Поскольку обычно заголовки содержат объявления, а исходные файлы содержат реализацию, люди понимают, что заголовки являются интерфейсами, публикуются c API, а исходные файлы содержат детали реализации. Это еще более подтверждается тем фактом, что в библиотеке пользователь (потребитель библиотеки) не видит содержимое исходных файлов, но может видеть заголовки.

Однако это неверно:

Заголовки
  • содержат определения (шаблоны, встроенные функции и переменные), заголовки
  • содержат объявления членов закрытого класса и символы с внутренней связью (stati c нелокальные и анонимные пространства имен). Это явно не является частью API.
  • библиотека предоставит символ (класс, функцию), даже если он используется исключительно внутри и не является частью API (если только он не используется только для один CU и выполненный с внутренней связью)
  • заголовок библиотеки будет вносить в код потребителя весь заголовок, который он использует, даже если некоторые из этих заголовков не нужны для API библиотеки. Это внесет ненужные символы в код пользователя, загромождая пространства имен.

Разделение заголовков и исходных файлов не выполняется на барьере интерфейса / реализации publi c. Такое разделение кода - просто артефакт того, как спроектирован C ++ с его наследием C. C ++ не требует многопроходного компилятора, поэтому он требует объявления перед использованием и одного определения. Таким образом, заголовки являются решением для этого. Они не являются спецификациями API.

Поэтому неудачный вывод состоит в том, что в C ++ нет разделения API / реализации, и попытка использовать заголовки для этого будет безуспешной.

Теперь ответим на ваш вопрос: Известный мне идиоматический способ c - это использование пространства имен details или impl. Понятно, что пространства имен, названные таким образом, содержат детали реализации библиотеки и не должны использоваться в пользовательском коде. Лично я не изменил бы ваш первоначальный дизайн.


C ++ 20 наконец-то включает модули, которые afaik решает эту проблему. И теперь у нас есть четкое разделение внутренних символов, которые не будут видны потребителю по сравнению с публичным c API.

0 голосов
/ 01 апреля 2020

Моя текущая идея состоит в том, чтобы включить и начало файла, и конец файла, включая один и тот же заголовок, и вместо того, чтобы дать ему защиту для включения, используя механизм двухкратного включения, с первым включением разоблачающие объявления и вторые разоблачающие определения, например что-то вроде:

#ifndef MY_DETAIL_HPP_TWICE
#ifndef MY_DETAIL_HPP_ONCE
#define MY_DETAIL_HPP_ONCE
#else
#define DEFINITIONS_VISIBLE
#define MY_DETAIL_HPP_TWICE
#endif // MY_DETAIL_HPP_ONCE

namespace detail {

inline void foo()
#ifndef DEFINITIONS_VISIBLE
;
#else
{ my_type x; do_foo_stuff(x); }
#endif

}
#endif // MY_DETAIL_HPP_TWICE

, но это кажется довольно надуманным, и я не видел, чтобы это использовалось где-либо.

...