Consider
#include <iostream>
#include <type_traits>
template <class T, class ARG_T = T&>
T foo(ARG_T v){
return std::is_reference<decltype(v)>::value;
}
int main() {
int a = 1;
std::cout << foo<int>(a) << '\n';
std::cout << foo<int, int&>(a) << '\n';
}
I'd expect the output to be 1 in both cases. But in the first case it's 0: consistent with the default being class ARG_T = T
rather than class ARG_T = T&
.
What am I missing?
For foo<int>(a)
, ARG_T
is being deduced from a
, and is not taken from the default template argument. Since it's a by value function parameter, and a
is an expression of type int
, it's deduced as int
.
In general, default template arguments are not used when template argument deduction can discover what the argument is.
But we can force the use of the default argument by introducing a non-deduced context for the function parameter. For instance:
template <class T, class ARG_T = T&>
T foo(std::enable_if_t<true, ARG_T> v1){
//...
}
Or the C++20 type_identity
utility, such as the other answer demonstrates.