模板默认参数丢失了它的引用类型

Template default argument loses its reference type

考虑

#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&.

一致

我错过了什么?

对于 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 实用程序,如其他答案所示。

你需要停止template argument deduction for ARG_T from the function argument v, (with the help of 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;
}

LIVE

顺便说一句:如果您的编译器不支持 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;