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?
You need to stop template argument deduction for
ARG_T
from the function argumentv
, (with the help ofstd::type_identity
, which could be used to exclude specific arguments from deduction); Otherwise, the default template argument won't be used. e.g.LIVE
BTW: If your compiler doesn't support
std::type_identity
(since C++20), you might make your own.For
foo<int>(a)
,ARG_T
is being deduced froma
, and is not taken from the default template argument. Since it's a by value function parameter, anda
is an expression of typeint
, it's deduced asint
.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:
Or the C++20
type_identity
utility, such as the other answer demonstrates.