2010-07-20 3 views
3

Я подробно расскажу о своей проблеме, чтобы объяснить, что я пытаюсь достичь, вопрос находится в последнем абзаце, если вы хотите игнорировать детали моей проблемы.C++ Template Specialization Compilation

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

Изготовление push() и pop() шаблонов, связанных stringstream - это очевидное решение. Тем не менее, я хочу использовать эту функциональность внутри DLL, в которой я могу изменить способ хранения строки (например, шифрование или сжатие) без перекомпиляции клиентов. Шаблон типа T необходимо будет перекомпилировать, если алгоритм изменится.

Моя следующая идея состояла в том, чтобы просто использовать такие функции, как pushByte(), pushInt(), popByte(), popInt() и т.д. Это позволило бы мне изменить реализацию без перекомпиляции клиентов, так как они полагаются только на статическом интерфейсе. Это было бы хорошо. Однако это не так гибко. Если значение было изменено с байта на короткий, например, все экземпляры pushByte(), соответствующие этому значению, необходимо было бы изменить на pushShort(), аналогично для popByte() - popShort(). Перегрузка pop() и push() для борьбы с этим вызовет конфликты в типах (что приведет к явному кастингу, что в конечном итоге приведет к одной и той же проблеме).

С вышеуказанными идеями я мог бы создать рабочий класс. Однако я задавался вопросом, как скомпилированы специализированные шаблоны. Если бы я создал push<byte>() и push<short>(), это была бы специфическая для типа перегрузка, а изменение с байта на короткий автоматически переключило бы используемый шаблон, что было бы идеально.

Теперь, мой вопрос: если бы я использовал специализированные шаблоны только для имитации такого перегрузки (без шаблона типа T), будут ли все специализации компилироваться в мою DLL, что позволит мне отправить новую реализацию без перекомпиляции клиента? Или специализированные шаблоны выбираются или удаляются так же, как шаблон типа T во время компиляции клиента?

+0

Некоторые указатели на специализацию шаблона и перегрузку от Herb Sutter. http://gotw.ca/gotw/049.htm – DumbCoder

+0

Почему для перегрузок требуется явное литье, которое пользователь переключает? –

+0

Если я передал короткую функцию, перегруженную с помощью push (byte), push (short) и push (int), не вызовет ли это конфликт, в котором функция может выбирать из push (short) и push (int)? Короткое может быть передано и в любом случае. –

ответ

2

Прежде всего, вы не можете только имеют специализированные шаблоны без базового шаблона для специализации. Это просто запрещено. Вы должны начать с шаблона, тогда вы можете предоставить специализации.

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

Я бы, наверное, просто перегрузил. Проблема, которую я предполагаю, что вы говорите, возникает с чем-то порядка:

int a; 
byte b; 

a = pop(); 
b = pop(); 

Где вы в основном просто быть перегрузки pop на возвращаемый тип (который, как мы все знаем, ISN» t разрешено).Я бы избежать, что довольно просто - вместо того, чтобы вернуться значение, передать ссылку на значение, которое будет изменено:

int a; 
byte b; 

pop(a); 
pop(b); 

Это позволяет не только разрешение перегрузки работы, но, по крайней мере, для меня выглядит чище, а (хотя, возможно, я только что написал слишком много ассемблера, поэтому я привык к таким вещам, как «pop ax»).

+0

И если вы хотите инициализации 'const', вы все равно можете предоставить оболочку:' template T pop_it() {T t; поп (т); return t; } '... или использовать фиктивный параметр:' a = pop (int()); ':) –

1

Похоже, у вас есть 2 разнонаправленных факторов:

  1. Вы хотите, чтобы ваши клиенты могли подтолкнуть/поп/и т.д.. каждый числовой тип. Шаблоны кажутся естественным решением, но это противоречит единообразной (только нужно компилировать) реализации.
  2. Вы не хотите, чтобы ваши клиенты перекомпилировались при изменении аспектов реализации. pimpl idiom кажется естественным решением, но это противоречит общей (работает с любым типом) реализации.

Из вашего описания, похоже, что вы только заботитесь о числовых типах, а не о произвольных Т. Вы можете объявить специализации своего шаблона для каждого из них явно в файле заголовка и определить их в исходном файле, а клиенты будут использовать определенные вами специализации, а не компилировать их самостоятельно. Специализации - это форма полиморфизма времени компиляции. Теперь вы можете комбинировать его с полиморфизмом времени выполнения - реализовать специализации в терминах класса реализации, который является агностиком типа. Ваш класс реализации мог бы использовать boost::variant для этого, так как вы знаете диапазон возможных T заранее (boost::variant<int, short, long, ...>). Если импульс не является для вас вариантом, вы можете придумать подобную схему самостоятельно, если у вас есть конечное число Ts, о котором вы заботитесь.