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

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

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);

}

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

2 ответа

Решение

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

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());
}

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

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

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

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

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

Другие вопросы по тегам