Как не связывать определенный объектный файл везде - PullRequest
1 голос
/ 16 июля 2011

Итак, я получил класс, который определяет константу со специальным значением для каждого типа.Я использую что-то подобное

template<class Type>
class SpecialKeyProvider
{
  static const Type SPECIAL_KEY;
}

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

// This seems to have to be in a cpp as having it in the same header, 
// will result in duplicate definitions of SPECIAL_KEY;

// This particular instantiation is kind of problematic anyways, see
// the end of my question for another question on this one.
template<>
string SpecialKeyProvider<string>::SPECIAL_KEY = "__SPECIAL";

template <class Type>
Type SpecialKeyProvider<Type> = std::numeric_limits<Type>::max();

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

Есть ли способ избавиться от этого и выполнить специализацию шаблона в заголовкебез получения ошибки из-за «нескольких определений»?

Второй вопрос, касающийся строковой константы.

// I know this is bad code but I don't know how to do it better.
template<>
string SpecialKeyProvider<string>::SPECIAL_KEY = "__SPECIAL";

Я знаю (и напоминание напоминает мне), что использование констант любого типа класса вообще плохая идея из-за неопределенного порядка построения( Руководство по стилю Google ), в частности строки.Хотя я обычно могу вместо этого использовать const char [], я не знаю, что делать в этом случае, так как я хочу, чтобы шаблон создавался для строк.Использование шаблона (т.е. использование моего класса контейнера, в котором использовался SpecialKeyProvider) с char * вместо этого было бы невероятно болезненным.

Я действительно благодарен за любой совет.

Ответы [ 2 ]

1 голос
/ 16 июля 2011

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

Более того, нет ничего плохого в статической (или динамической) библиотеке, одним из членов которой является SpecialKeyProvider.o, которая должна быть связана с каждым проектом. Еще раз, ваш make-файл или IDE должны иметь возможность обрабатывать библиотеки.

Что касается руководства по стилю Google, оно не одно из лучших. Это руководство по стилю для языка, который лучше называется C ±, чем C ++. Они запрещают использование неконстантных ссылок, потому что иногда люди могут быть сбиты с толку. Здесь они запрещают использование статических глобальных переменных типа класса, потому что иногда это может привести к фиаско в статическом порядке инициализации.

Запретить какую-то оптовую торговлю, потому что при некоторых обстоятельствах люди могут злоупотреблять этим, ИМХО плохая практика Черт возьми, назови одну часть C ++, которую какой-то коварный программист не нашел способа злоупотребить.

Где, собственно, взаимозависимости в ваших определениях тех SpecialKeyProvider<Type>::SPECIAL_KEY, которые даже фиаско применяют статический порядок инициализации?

1 голос
/ 16 июля 2011

Поместите class с static const в безымянное пространство имен в заголовочном файле:

namespace
{
  template<class Type>
  class SpecialKeyProvider
  {
    static const Type SPECIAL_KEY;
  };
  template<>
  const string SpecialKeyProvider<string>::SPECIAL_KEY = "__SPECIAL";  //<--- const

  template<>
  const double SpecialKeyProvider<double>::SPECIAL_KEY = 3.3;  //<--- const
}

Это не приведет к ошибке компоновщика, даже если вы объявите переменные взаголовочный файл;Потому что для каждого файла .cpp создается другое безымянное namespace.В вашем случае у вас объявлено только const переменных, поэтому есть уверенность, что все файлы .cpp читают одно и то же значение.

Редактировать : Что касается вашего второго вопроса, я не понимаюНе знаю, в чем может быть проблема с вышеуказанным подходом, так как для каждой единицы перевода будет создана отдельная копия const.Посмотрите, жалуется ли еще пух.

...