I want to have my template function print
(The actual cenario is more complex template function) to have either a const T&
or just T
(pass by value), depending up on the characteristics of type T
.
In other words, if a type T
is easily copyable (i.e. such as primitive types int
, float
, double
, std::initializer_list<>
, trivially copyable, etc...) and does not make a lot of copying effort, I want to have template instatiation pass by value, otherwise a const l-value reference to the passed type T
.
After researching I figured out the folloing two way of doing it.
I tried with both std::conditional_t
as well as if constexpr
function decltype
ing as follows:
#include <type_traits>
#include <iostream>
#include <string>
using namespace std::string_literals;
#if 1 // template function way --- (1)
template<typename T>
constexpr auto type_helper() noexcept
{
if constexpr (std::is_fundamental_v<T>) return T{};
else return std::add_const_t<std::add_lvalue_reference_t<T>>{};
};
template<typename T> using conditional_copy_ref_t = decltype(type_helper<T>());
#elif 0 // using std::conditional_t --- (2)
template<typename T>
using conditional_copy_ref_t = std::conditional_t<std::is_fundamental_v<T>, T, const T&>;
#endif
template <typename T>
auto print(conditional_copy_ref_t<T> arg) noexcept
// could not deduce template ^^^^^^^^^^^^ argument for 'T'
{
// do something with arg!
};
int main()
{
print(5); // should be pass by value
print("string"s);// should be const std::string&
}
Here is the code in online compilers: https://gcc.godbolt.org/z/5fEaE3M5o
However, both the implementations fails due to the fact of non-deduced context template deduction(I have researched agin to understand the error)!
In MSVS I have the error:
error C2672: 'print': no matching overloaded function found
error C2783: 'auto print(unknown-type) noexcept': could not deduce template argument for 'T'
What am I doing wrong? Is it even possible? How to fix this error and get the correct type here?
CodePudding user response:
Because T
is in a non-deduced context, there is no way for the compiler to deduce the type of T
. Instead, you can use enable_if
to help the compiler deduce the type of T
template <typename T>
std::enable_if_t<std::is_fundamental_v<T>>
print(T) noexcept { /* */ }
template <typename T>
std::enable_if_t<!std::is_fundamental_v<T>>
print(const T&) noexcept { /* */ }
CodePudding user response:
You can tell the compiler what T
is explicitly so it doesn't have to deduce it:
#include <type_traits>
#include <iostream>
#include <string>
template<typename T>
using conditional_copy_ref_t = std::conditional_t<std::is_fundamental_v<T>, T, const T&>;
template <typename T>
auto print(conditional_copy_ref_t<T> arg) noexcept
{
};
int main()
{
print<int>(5);
print<std::string>("string");
}