Использование шаблона класса в шаблоне функции с универсальным эталонным параметром
Согласно msvc, gcc и clang, следующий код является незаконным:
template <typename T>
void f(T&& e) {
std::vector<T> v;
// do something with v and e ...
}
int main() {
int i;
f(i);
}
msvc дает
xmemory0 (591): ошибка C2528: "указатель": указатель на ссылку незаконное
gcc и clang дают похожие звуковые сообщения об ошибках. Обратите внимание, что универсальный опорный параметр e
не используется. Компилятор, очевидно, не создает экземпляр вектора v
, жалуясь на то, что он используется со ссылкой на int
:
note: см. ссылку на экземпляр шаблона класса 'std::vector<T,std::allocator<_Ty>>'
скомпилировано с
[
T=int &,
_Ty=int &
]
Но я не вижу, где создается шаблон функции f
со ссылкой на int
.
Может кто-нибудь объяснить ошибки компилятора, которые мы видим здесь?
Ответы
Ответ 1
Когда f
вызывается с lvalue int
, T
будет выводиться как int&
, поэтому v
будет std::vector<int&>
. Это неверно.
Один из способов обойти это - удалить ссылки из T
перед его использованием:
template <typename T>
void f(T&& e) {
using value_type = typename std::remove_reference<T>::type;
//using value_type = std::remove_reference_t<T>; for C++14
std::vector<value_type> v;
// do something with v and e ...
}
Однако, если вы хотите, чтобы функция была как можно более общей, вы должны использовать std::decay
вместо std::remove_reference
. Это позволит f
работать с cv-квалифицированными типами, массивами и функциями.
Ответ 2
Скотт Майерс объясняет в этой статье .
Если выражение, инициализирующее универсальную ссылку, является значением l, универсальная ссылка становится ссылкой lvalue.
Если выражение инициализация универсальной ссылки - это rvalue, универсальная ссылка становится ссылкой rvalue.
В вашем случае i
является lvalue и поэтому T
выводится как int&
.