Пересылка ссылок и шаблонов

Рассмотрим эти две функции шаблона:

template<typename T>
void foo(T&& bar) {
    // do stuff with bar, which may or may not be an instance of a templated class
}

template<typename U, template<typename> class T>
void foo(T<U>&& bar) {
    // do stuff with bar, which must be an instance of a templated class
}

Почему первый принимает lvalues ​​(используя ссылку пересылки), а второй нет?


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

2 ответа

Решение

Потому что так сказано в стандарте, язык должен работать.

[14.8.2.1] [temp.deduct.call]
3.Если P является cv-квалифицированным типом, cv-квалификаторы верхнего уровня типа P игнорируются при выводе типа. Если P является ссылочным типом, тип, на который ссылается P, используется для вывода типа. Ссылка для пересылки - это rvalue-ссылка на неквалифицированный cv параметр шаблона. Если P является ссылкой для пересылки, а аргумент является lvalue, тип "lvalue ссылка на A" используется вместо A для вывода типа.

Таким образом, в качестве ссылки на l-значение можно вывести только rvalue-ссылку на CV-неквалифицированный параметр шаблона.

Чтобы добиться того, что вы пытаетесь сделать, вы можете использовать черту для извлечения параметра шаблона шаблона.

#include <type_traits>

/***
 * Extract template from template type.
 */
template <typename I> struct get_template;

template <template<class> typename T, typename C>
struct get_template<T<C>> {
  template <typename U>
  using temp = T<U>;
};





template <typename T> struct A{};

struct B;

template<typename W>
void foo(W && bar) {
  typedef typename get_template<typename std::remove_reference<W>::type>::template temp<int> new_type;
  new_type my_variable;
}

int main() {
  A<B> temp;
  foo(temp);
}

Или просто перегрузите функцию для const & и && как обычно.

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

#include <type_traits>
#include <utility>

template <typename T>
struct tag {};

template <typename T, typename U, template <typename> class C>
void foo(T&& t, tag<C<U>>)
{

}

template <typename T>
auto foo(T&& t)
    -> decltype(foo(std::forward<T>(t), tag<typename std::decay<T>::type>{}))
{
    return foo(std::forward<T>(t), tag<typename std::decay<T>::type>{});
}

DEMO

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