C++ 模板默认参数将丢失其引用类型

C++ 模板默认参数将丢失其引用类型,c++,templates,function-templates,template-argument-deduction,C++,Templates,Function Templates,Template Argument Deduction,考虑 #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)

考虑

#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';
}
#包括
#包括
模板
T foo(ARG_T v){
返回std::is_reference::value;
}
int main(){
INTA=1;
std::cout对于
foo(a)
ARG\u T
是从
a
推导而来的,不是从默认模板参数中获取的。因为它是一个按值函数参数,
a
是类型
int
的表达式,所以它被推导为
int

通常,当模板参数推断可以发现参数是什么时,不使用默认模板参数

但我们可以通过为函数参数引入非推断上下文来强制使用默认参数。例如:

template <class T, class ARG_T = T&>
T foo(std::enable_if_t<true, ARG_T> v1){
    //...
}
模板
T foo(标准::如果v1,则启用){
//...
}
或者C++20
type_identity
实用程序,如另一个答案所示。

您需要从函数参数
v
中停止以获取
ARG\T
,(在的帮助下,它可以用于从推导中排除特定参数);否则,将不使用默认模板参数。例如

template <class T, class ARG_T = T&>
T foo(std::type_identity_t<ARG_T> v){
    return std::is_reference<decltype(v)>::value;
}

好的,只是想澄清一下(在回答了一些复杂的问题之后):您的问题与默认参数无关,因为这两个示例中都没有使用它。对于那些仍然不理解的人:
=t&
如果可以推断出
ARG\u t
,则完全忽略它。这个问题的答案很好,但为什么不只是
template t foo(t&);
如果你想推断reference@sudo-这将使
T
可推断,这是它最初不是的东西。@StoryTeller如果这是目标,那么我会选择类型_标识,而不需要一秒钟的间接定向argument@sudo-第二个参数可能有更多用途。它是实现函数的方便类型别名。这个答案应该清楚地表明,这是一个C++20特性,现在是2019年,并且现有的主要编译器中没有一个完全支持C++20的特性。
template<typename T> struct type_identity { typedef T type; };
template< class T >
using type_identity_t = typename type_identity<T>::type;