Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Template default argument loses its reference type

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?

like image 938
Bathsheba Avatar asked Sep 06 '19 10:09

Bathsheba


People also ask

CAN default arguments be used with the template?

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 { };

Can template parameters have default values?

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.

What is template argument in C++?

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.

How many template arguments are there?

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.


2 Answers

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.

like image 123
StoryTeller - Unslander Monica Avatar answered Sep 29 '22 16:09

StoryTeller - Unslander Monica


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; 
like image 34
songyuanyao Avatar answered Sep 29 '22 16:09

songyuanyao