Точки настройки на основе признаков и проблемы нарушения ODR в {fmt} - PullRequest
0 голосов
/ 30 октября 2018

Во-первых, я сейчас изучаю C ++ для своей диссертации и поэтому не знаю языка. Любая помощь приветствуется.

Я использую библиотеку fmt в своем коде, и канонический способ форматирования предоставленных пользователем типов заключается в специализации типа шаблона класса fmt::formatter.

Пример

Код в проводнике компилятора: https://godbolt.org/z/2VO_wa

Имеются две библиотеки A и B, которые обе часто используют fmt в своей реализации, и обе они так или иначе нуждаются в печати / протоколировании текущего времени. Оба могут разумно использовать std::chrono::system_clock, и, желая отформатировать его в нескольких точках, каждый определяет свою собственную версию fmt::formatter<std::chrono::system_clock::time_point>, чтобы сделать этот простой код возможным:

auto msg = fmt::format("It is now {}", std::chrono::system_clock::now());

Библиотека A использует реализацию, отличную от B, поскольку вместо печати в формате UTC учитывается местный часовой пояс.

Теперь этот пример очень специфичен, но поскольку шаблон класса fmt::formatter - это способ форматирования пользовательских типов, этот сценарий может происходить в той или иной форме.

Проблема

Когда я разрабатываю свое приложение C и использую обе (не связанные) библиотеки A и B, тогда я полагаю, что будут две разные реализации одного и того же типа (а именно fmt::formatter<std::chrono::system_clock::time_point>), таким образом нарушая ODR с неопределенным поведение.

Вопрос

Если я правильно понимаю ситуацию, у меня два вопроса:

  1. Есть ли способ избежать этого конфликта в приложении C без изменения A и B upstream?
  2. Если можно изменить A или B (или оба), каким образом конфликт может быть разрешен или полностью предотвращен.

1 Ответ

0 голосов
/ 30 октября 2018
  1. Есть ли способ избежать этого конфликта в приложении C без изменения A и B в восходящем направлении?

У вас действительно есть нарушение ODR, я не думаю, что вы можете избежать конфликта, не изменяя A и / или B.

  1. Если можно изменить А или В (или оба), каким образом конфликт может быть разрешен или полностью предотвращен.

Специализируйте только типы вашей собственной библиотеки: поэтому в библиотеке A создайте обертку вокруг std::chrono::system_clock::time_point

 namespace A {
     struct TimePoint {
         std::chrono::system_clock::time_point timePoint;
     };
 }


namespace fmt {
     // Specialization of formatter<TimePoint>
}

, а затем

auto msg = fmt::format("It is now {}", A::TimePoint{std::chrono::system_clock::now()});

То же самое для библиотеки B.

...