Considérer
#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';
}
Je m'attendrais à ce que la sortie soit 1 dans les deux cas. Mais dans le premier cas, c'est 0: cohérent avec la valeur par défaut class ARG_T = T
plutôt que class ARG_T = T&
.
Qu'est-ce que je rate?
Pour foo<int>(a)
, ARG_T
est déduit de a
et n'est pas extrait de l'argument de modèle par défaut. Puisqu'il s'agit d'un paramètre de fonction par valeur et que a
est une expression de type int
, il est déduit comme int
.
En général, les arguments de modèle par défaut ne sont pas utilisés lorsque la déduction d'argument de modèle peut découvrir ce qu'est l'argument.
Mais nous pouvons forcer l'utilisation de l'argument par défaut en introduisant un contexte non déduit pour le paramètre de fonction. Par exemple:
template <class T, class ARG_T = T&>
T foo(std::enable_if_t<true, ARG_T> v1){
//...
}
Ou le C++ 20 type_identity
utilitaire, comme le montre l'autre réponse.
Vous devez arrêter déduction d'argument de modèle pour ARG_T
à partir de l'argument de la fonction v
, (à l'aide de std::type_identity
, qui pourrait être utilisé pour exclure des arguments spécifiques de la déduction); Sinon, l'argument de modèle par défaut ne sera pas utilisé. par exemple.
template <class T, class ARG_T = T&>
T foo(std::type_identity_t<ARG_T> v){
return std::is_reference<decltype(v)>::value;
}
BTW: si votre compilateur ne prend pas en charge std::type_identity
(depuis C++ 20), vous pouvez créer le vôtre.
template<typename T> struct type_identity { typedef T type; };
template< class T >
using type_identity_t = typename type_identity<T>::type;