Пойдем по порядку
template <class T>
void func(std::vector<T> && param) {}
std::vector<int> vec;
func(vec);
Снова проверка на универсальную ссылку. Только в формате Т&& параметр шаблонной функции может называться универсальной ссылкой. Здесь такого нет.
Мы передает обычный lvalue в функцию, оно не сможет кастануться к rvalue reference, поэтому будет ошибка компиляции.
template <class T>
void vector(const T & param) {}
vector({1, 2, 3});
Интересный случай. Потому что мы все знаем приколы с конструкторами вектора, и их стремлению интерпретировать набор объектов внутри фигурных скобок как std::initializer_list. Я даже назвал функцию vector, чтобы вас надурить немного. Да и по правилам вывода типов auto, {1, 2, 3} тоже выведется в std::initializer_list. Но вывод в шаблонах - это другое. Компилятор не может правильно интерпретировать, что за сущность мы пытаемся засунуть в функцию, поэтому откажется это компилировать.
template <class T>
void func(std::shared_ptr<const T> & ptr) {}
func(std::shared_ptr<const int>{});
Вроде как должно быть int, но если внимательно присмотреться к сигнатуре функции, то можно рассмотреть, что она принимает неконстантную ссылку. А временный объект, который мы в нее передаем, не сможет привестить к неконстантной ссылке. Поэтому снова будет ошибка компиляции.
template <class T>
void func(T&& param) {}
const std::vector<int> vec;
func(vec);
Нет, здесь не будет ошибки компиляции. Слишком много уловок - нехорошо. Тут просто хороший кейс на проверку полноты усвоенного материала. Здесь param - универсальная ссылка. Передаем мы в функцию lvalue, а это значит, что тип Т точно будет ссылкой. Вопрос на что. Здесь никакой вложенности нет, поэтому ничего от типа
vec не убираем, а только добавляем сслочность. Ответ - const std::vector<int>&.Check your knowledge. Stay cool.