Могу ли я определить тип ссылки на значение rvalue?

#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 .