Аргумент шаблона по умолчанию теряет свой ссылочный тип
Рассмотреть возможность
#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';
}
Я ожидал, что в обоих случаях на выходе будет 1. Но в первом случае это 0: в соответствии со значением по умолчанию.class ARG_T = T
скорее, чем class ARG_T = T&
.
Что мне не хватает?
2 ответа
За foo<int>(a)
, ARG_T
выводится из a
, и не берется из аргумента шаблона по умолчанию. Поскольку это параметр функции по значению, иa
это выражение типа int
, это выводится как int
.
Как правило, аргументы шаблона по умолчанию не используются, если вывод аргументов шаблона может обнаружить, что это за аргумент.
Но мы можем принудительно использовать аргумент по умолчанию, введя невыведенный контекст для параметра функции. Например:
template <class T, class ARG_T = T&>
T foo(std::enable_if_t<true, ARG_T> v1){
//...
}
Или C++20 type_identity
утилита, например, демонстрирует другой ответ.
Вам необходимо остановить вывод аргументов шаблона дляARG_T
из аргумента функции v
, (с помощью std::type_identity
, который можно использовать для исключения определенных аргументов из дедукции); В противном случае аргумент шаблона по умолчанию не будет использоваться. например
template <class T, class ARG_T = T&>
T foo(std::type_identity_t<ARG_T> v){
return std::is_reference<decltype(v)>::value;
}
Кстати: если ваш компилятор не поддерживает std::type_identity
(начиная с C++20), вы можете создать свой собственный.
template<typename T> struct type_identity { typedef T type; };
template< class T >
using type_identity_t = typename type_identity<T>::type;