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 cannot give default arguments to the same template parameters in different declarations in the same scope. The compiler will not allow the following example: template<class T = char> class X; template<class T = char> class X { };
Just like in case of the function arguments, template parameters can have their default values. All template parameters with a default value have to be declared at the end of the template parameter list.
In C++ this can be achieved using template parameters. A template parameter is a special kind of parameter that can be used to pass a type as argument: just like regular function parameters can be used to pass values to a function, template parameters allow to pass also types to a function.
1) A template template parameter with an optional name. 2) A template template parameter with an optional name and a default. 3) A template template parameter pack with an optional name.
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.
You need to stop template argument deduction for ARG_T
from the function argument v
, (with the help of std::type_identity
, which could be used to exclude specific arguments from deduction); Otherwise, the default template argument won't be used. e.g.
template <class T, class ARG_T = T&> T foo(std::type_identity_t<ARG_T> v){ return std::is_reference<decltype(v)>::value; }
LIVE
BTW: If your compiler doesn't support std::type_identity
(since C++20), you might make your own.
template<typename T> struct type_identity { typedef T type; }; template< class T > using type_identity_t = typename type_identity<T>::type;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With