I have a serialize function that performs differently based on the type. I'd like to be able to call it with both f(x)
and f(5)
, but f(5)
fails with error No matching function for call to 'f', Candidate function [with T = int] not viable: expects an l-value for 1st argument.
If I change f(T& t)
to f(T&& t)
then f(x)
is not arithmetic. How can I recognize both f(x)
and f(5)
to be arithmetic, and similarly for any type such as the string type below? I don't want to force the input to be const because I want to alter it otherwise.
template<typename T>
void f(T& 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;
}
You can use a forwarding reference, T&&
, to take the argument by either lvalue- or rvalue reference depending on what's passed in.
In case of lvalue, T = int&
, so we need to use std::decay_t
to remove the reference from the type.
When we pass an rvalue, T = int
and decay does nothing.
#include <type_traits>
#include <string>
#include <iostream>
template<typename T>
void f(T&& 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;
}
Note that std::decay
performs
Applies lvalue-to-rvalue, array-to-pointer, and function-to-pointer implicit conversions to the type T
If any of those cases is not desired, you can use a combination of std::remove_reference
and std::remove_const
, or in case of c++20 we can use std::remove_cvref
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.