Я пишу этот код

#include <iostream>
#include <string>


template <typename T>
void Print(T& value)
{
    std::cout << value << std::endl;
}

int main()
{
    Print("Hello");
    Print(1);
}

И при компиляции компиляторы сказали ошибку, что "void Print<int>(T &)' : cannot convert argument 1 from 'int' to 'T &'". Но Print("Hello") не выдало ошибку. Почему так?

И я изменил функцию Print() на

void Print(T value)
{
    std::cout << value << std::endl;
}

Это сработало. Но я не понимаю, почему прежний код не работал.

0
passer-by 18 Янв 2022 в 15:34

3 ответа

Случай 1

Здесь мы рассмотрим, как работает Print(1);.

В этом случае проблема заключается в том, что 1 является rvalue, и вы пытаетесь привязать это rvalue к ссылке lvalue на неконстантное T(то есть T&), что невозможно и, следовательно, ошибка. Например, вы не можете иметь:

void Print(int &value)
{
    std::cout << value << std::endl;
}

int main()
{
   Print(1);// won't work
}

Решение

Таким образом, чтобы решить вашу проблему, вы можете использовать ссылку lvalue на const T(то есть const T&), которую можно привязать к rvalue, как показано ниже:

template <typename T>
void Print(const T& value)//note the const added here
{
    std::cout << value << std::endl;
}
int main()
{
   
    Print(1); //works now
}

Дело 2

Здесь мы рассматриваем утверждение Print("Hello");

В этом случае "Hello" — это строковый литерал. и имеет тип const char [6]. Кроме того, строковый литерал "Hello" является lvalue.

И мы знаем, что можем связать lvalue со ссылкой lvalue на неконстантный T(то есть T&). Так что в данном случае ошибки нет. Также обратите внимание, что в этом случае T выводится как const char [6].

Заметка

В случае 2 выше (Print("Hello");) распада типа нет, потому что аргумент передается по ссылке, а не по значению.

3
Anoop Rana 18 Янв 2022 в 16:18
1
Да, это хороший ответ, проголосуйте.
 – 
Bathsheba
18 Янв 2022 в 16:06
Отличный ответ! Спасибо вам за помощь!
 – 
passer-by
18 Янв 2022 в 16:27

Из-за этого:

test.cpp:45:11: error: cannot bind non-const lvalue reference of type 'int&' to an rvalue of type 'int'
   45 |     Print(1);
      |           ^

Поэтому преобразуйте его в универсальную ссылку:

template <typename T>
void Print( T&& value ) // notice &&, that's a universal reference, not an rvalue ref
{
    std::cout << value << std::endl;
}
2
digito_evo 18 Янв 2022 в 15:43
1
Порезал вашу привязку. Проголосуйте за хорошее настроение ;-)
 – 
Bathsheba
18 Янв 2022 в 15:45

1 является rvalue и поэтому не может быть привязан к T&. Однако он может связываться с const T&.

То есть,

void Print(const T& value)

Или

void Print(T&& value)

Являются исправлениями.

1
Bathsheba 18 Янв 2022 в 16:06
Большой! Спасибо!
 – 
passer-by
18 Янв 2022 в 16:30