В настоящее время я пишу класс шаблона для архивирования (или сериализации) и распаковки данных в/из двоичного формата. Во-первых, я пытаюсь закрыть, какую модель я буду использовать. Я в основном склонен к использованию шаблонов, потому что у unarchivers нет типа ввода для перегрузки метода. Например, следующий пример OK:Парадигма относительно специализации класса шаблонов
Archiver ar;
int i;
archive(ar, i);
Но это аналог не:
Unarchiver unar;
int i;
i = unarchive(unar);
Я хотел бы избежать, используя имя функции, такие как unarchive_int
, потому что это будет хлопотно при использовании шаблоны. Скажи:
template <class T> class SomeClass
{
public:
void doSomething()
{
// Somewhere
T value = unarchive(unar);
}
};
Это сделало бы вещи неаккуратно, и как таковой я, а на самом деле использовать шаблоны для этого, в то время как предыдущее выражение будет T value = unarchive<T>(ar);
. Также кажется глупо (возможно) писать глобальную функцию, если либо первый, либо единственный параметр всегда являются объектами архиватора и unarchiver; класс шаблона, кажется, в порядке:
template <class T> class Archiver
{
public:
void archive(T obj);
};
Это работает, но метод архивации всегда копирует свой входной объект. Это нормально с типами данных POD, но не столько для классов. Решение кажется очевидным и вместо этого использует ссылку на константу как в void archive(const T & obj)
, но теперь также кажется глупым передавать целые числа, поплавки и другие POD по ссылке. Хотя я был бы доволен этим решением, я попытался пойти немного дальше и сделать объект вместо этого. Мой первый подход - std::enable_if
, при этом предполагается, что по умолчанию используется копия (для всех членов, не относящихся к классу), и предоставлена специализация класса, где метод archive
получает свой ввод по ссылке вместо этого. Это не работает. Вот код:
template <class T, class E = void>
class Archiver
{
public:
// By default, obj is passed by copy
void archive(T obj);
};
template <class T>
class Archiver<T, typename std::enable_if<std::is_class<T>::value && !std::is_pod<T>::value>::value>
{
public:
// I would expect this to be used instead if is_class<T> && !is_pod<T>
void archive(const T & obj);
};
Проблема заключается в том, что вторая декларация не видна на всех компилятором, и вот доказательство:
template <> void Archiver<std::uint8_t>::archive(uint8_t obj);
template <> void Archiver<std::string>::archive(const std::string & obj);
Бывший компилируется нормально, но потом дает:
вне линии декларирование «архива» не соответствует ни одной декларации в
'Archiver<std::__1::basic_string<char>, void>'
С другой стороны, если я получу std::string
вместо копии, если компилируется просто отлично. Я думаю, что я знаю, почему это происходит, компилятор выбирает первый шаблон, поскольку он достаточно общий для обеих деклараций, но как же я могу выбрать более специализированную версию?
Обратите внимание, что вы можете передать некоторые типы POD в качестве ссылки. Просто потому, что это тип POD, это не значит, что быстро перейти к функции (в частности, если это большой тип POD). – Cornstalks
@ Корнисторы да, я знаю. Это «первый подход», я сначала пытаюсь решить эту проблему с разрешением, тогда я буду рассматривать, какие типы передаются копией и которые передаются по ссылке;), но спасибо за головы! –
Я откат вашего редактирования. Пожалуйста, не меняйте вопрос (и ваше редактирование, конечно, изменило бы вопрос), поскольку это превращает вопрос в движущуюся цель. Вместо этого откройте новый вопрос или добавьте дополнительный раздел к вопросу с новыми ошибками кода/новых. – Cornstalks