Специализация шаблона функции, который принимает универсальный ссылочный параметр

Как специализировать шаблон функции, который принимает универсальный ссылочный параметр?

foo.hpp:

template<typename T>
void foo(T && t)    // universal reference parameter

foo.cpp

template<>
void foo<Class>(Class && class) {
// do something complicated
}

Вот, Class больше не выводимый тип и, следовательно, Class именно так; это не может быть Class &, поэтому правила свертывания ссылок здесь мне не помогут. Я мог бы, возможно, создать другую специализацию, которая занимает Class & параметр (я не уверен), но это подразумевает дублирование всего кода, содержащегося в foo для каждой возможной комбинации ссылок rvalue / lvalue для всех параметров, чего должны избегать универсальные ссылки.

Есть ли способ сделать это?

Чтобы быть более конкретным о моей проблеме в случае, если есть лучший способ ее решения:

У меня есть программа, которая может подключаться к нескольким игровым серверам, и каждый сервер, по большей части, вызывает все с одинаковым именем. Тем не менее, у них есть несколько разные версии для нескольких вещей. Есть несколько различных категорий, которыми могут быть эти вещи: перемещение, элемент и т. Д. Я написал общий набор функций «переместить строку для перемещения» для вызова внутреннего кода, и мой код интерфейса сервера имеет аналог функции. Однако некоторые серверы имеют свои собственные внутренние идентификаторы, с которыми они взаимодействуют, некоторые используют строки, а некоторые используют оба в разных ситуациях.

Теперь я хочу сделать это немного более общим.

Я хочу быть в состоянии назвать что-то вроде ServerNamespace::server_cast<Destination>(source), Это позволило бы мне бросить из Move к std::string или же ServerMoveID, Внутренне мне может потребоваться сделать копию (или переместиться), потому что некоторые серверы требуют, чтобы я вел историю отправленных сообщений. Универсальные ссылки кажутся очевидным решением этой проблемы.

Заголовочный файл, о котором я сейчас думаю, будет представлен просто так:

namespace ServerNamespace {

template<typename Destination, typename Source>
Destination server_cast(Source && source);

}

И файл реализации будет определять все легальные преобразования как шаблонные специализации.

9

Решение

На мой взгляд, лучшим решением является использование системы диспетчеризации тегов, в которой вы перегружаете теги, а не фактический тип:

struct foo {
struct tag {};
};

struct bar {
struct tag {};
};

template<typename Destination, typename Source>
Destination server_cast(Source && source, foo::tag) {
// foo
}

template<typename Destination, typename Source>
Destination server_cast(Source && source, bar::tag) {
// bar
}

template<typename Destination, typename Source>
Destination server_cast(Source && source) {
return server_cast<Destination>(std::forward<Source>(source), typename std::remove_reference<Source>::type::tag());
}
2

Другие решения

Самое расширяемое, что нужно сделать, это создать специализацию класса шаблона.

template< class X > struct Whatever {
void f(){ ... }
};

template<> struct Whatever<UserType> {
void f(){ ... }
};

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

Это является дополнительным, а не исключительным, для решения по отправке тегов, предложенного Pubby.

1

По вопросам рекламы [email protected]