Идеальная пересылка и std :: tuple (или другой шаблонный класс) - PullRequest
6 голосов
/ 25 ноября 2011

У меня есть некоторые трудности с идеальной пересылкой.

Вот мой текущий уровень понимания: склейка Template + rvalue reference + std :: forward и специальный магический режим активируются, когда правила вычитания шаблона не имеют того значения, как обычно, но созданы так, чтобы обеспечить идеальную пересылку,Пример:

template <typename T>
void outer(T&& t)
{
   inner(std::forward<T>(t)); // perfect forwarding activated
}

Но что произойдет, если T на самом деле является шаблонным классом?Например, как я могу совершить пересылку std :: tuple?Если использовать T && в качестве aboce, я потеряю всю информацию о типах объектов, содержащихся в кортеже.
Однако следующий код не может работать:

template <typename... Args>
void outer(std::tuple<Args...>&& t) 
{
   inner(std::forward<std::tuple<Args...>>(t));
   use_args_types_for_something_else<Args...>(); // I need to have Args available
}

int main()
{
   std::tuple<int, double, float> t(4, 5.0, 4.0f);
   outer(t);
}

Последний снимок gcc говорит:

error: cannot bind 'std::tuple<int, double, float> lvalue to
std::tuple<int, double, float>&&

Очевидно, что мы все еще находимся в общем не шаблонном случае, когда lvalue не может связываться со ссылкой на rvalue.«Идеальный режим пересылки» не активирован

Поэтому я попытался быть хитрым и передать свой кортеж в качестве шаблона шаблона:

template <
  typename... Args
  template <typename...> class T
>
void outer(T<Args...>&& t) 
{
   inner(std::forward<T<Args...>>(t));
   use_args_type_for_something_else<Args...>(); 
}

Но я все еще получаю ту же ошибку.

1 Ответ

3 голосов
/ 26 ноября 2011

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

template <typename T>
void outer(T&& t)
{
   inner(std::forward<T>(t)); // perfect forwarding activated
}

Сказанное выше работает, потому что оноэто особый случай, когда T выводится как SomeType& или SomeType&&.

Это, однако, не означает, что информация о типе элементов кортежа потеряна навсегда.Он по-прежнему доступен для поиска (хотя я не думаю, что вы можете набрать переменный пакет шаблонов).Например, вы все еще можете вызвать use_args_types_for_something_else следующим образом:

template <class T>
struct call_uses_args;

template <class ...Args>
struct call_uses_args<std::tuple<Args...>>
{
    void call() const { use_args_types_for_something_else<Args...>(); }
};

template <typename TupleT>
void outer(TupleT&& t)
{
   inner(std::forward<TupleT>(t));
   call_uses_args<typename std::remove_reference<TupleT>::type>().call();
}

Хотя, возможно, не существует хорошего общего решения, но, надеюсь, такие ситуации встречаются редко.(Например, в этом конкретном примере может быть проще просто перегрузить outer.)

...