#c #templates
#c #шаблоны
Вопрос:
У меня есть функция сериализации, которая выполняется по-разному в зависимости от типа. Я хотел бы иметь возможность вызывать его с помощью обоих f(x)
и f(5)
, но f(5)
сбой с ошибкой No matching function for call to 'f', Candidate function [with T = int] not viable: expects an l-value for 1st argument.
, если я изменяю f(Tamp; t)
на f(Tamp;amp; t)
then f(x)
, не является арифметическим. Как я могу распознать оба f(x)
и f(5)
быть арифметическими, и аналогично для любого типа, такого как строковый тип ниже? Я не хочу принудительно вводить значение const, потому что я хочу изменить его в противном случае.
template<typename T>
void f(Tamp; t)
{
if constexpr (std::is_arithmetic_v<T>)
{
// do stuff
}
else if constexpr (std::is_same_v<T, std::string>)
{
// do other stuff
}
else
{
//alter non-const input
}
}
int main()
{
int x;
f(x);
f(5);
return 0;
}
Комментарии:
1. Почему бы вместо этого не использовать аргумент by
constamp;
?2. @cigien. Извините, я забыл упомянуть, что я не хочу делать его постоянным. Я отредактировал вопрос.
3. Хорошо, не могли бы вы объяснить, что значит изменять
5
? Если вы просто хотите изменить копию, тогда примите аргумент по копии, т.е.T t
.4. @cigien. Я не хочу изменять 5. Я хочу, чтобы 5 попадало в блок is_arithmetic .
5. Ваш код уже выполняет эту часть правильно. Я должен был уже спросить об этом, но, пожалуйста, вставьте также сообщение об ошибке.
Ответ №1:
Вы можете использовать ссылку пересылки, Tamp;amp;
, чтобы принять аргумент либо по ссылке lvalue, либо по ссылке rvalue в зависимости от того, что передается.
В случае lvalue , T = intamp;
, поэтому нам нужно использовать std::decay_t
для удаления ссылки из типа.
Когда мы передаем значение rvalue, T = int
и decay ничего не делает.
#include <type_traits>
#include <string>
#include <iostream>
template<typename T>
void f(Tamp;amp; t)
{
using T_Type = std::decay_t<T>; // remove const/reference from the type
if constexpr (std::is_arithmetic_v<T_Type>)
{
// do stuff
}
else if constexpr (std::is_same_v<T_Type, std::string>)
{
// do other stuff
}
else
{
//alter non-const input
}
}
int main()
{
int x;
f(x);
f(5);
return 0;
}
Обратите внимание, что std::decay
выполняет
Применяет неявные преобразования lvalue-to-rvalue, array-to-pointer и function-to-pointer к типу T
Если какой-либо из этих случаев нежелателен, вы можете использовать комбинацию std::remove_reference
и std::remove_const
, или в случае c 20 мы можем использовать std::remove_cvref
.