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

Bat*_*eba 43 c++ templates function-templates template-argument-deduction 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) << '\n';
    std::cout << foo<int, int&>(a) << '\n';
}
Run Code Online (Sandbox Code Playgroud)

我希望两种情况下的输出均为1。但在第一种情况下为0:与默认值class ARG_T = T而不是一致class ARG_T = T&

我想念什么?

Sto*_*ica 43

对于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){
    //...
}
Run Code Online (Sandbox Code Playgroud)

或C ++ 20 type_identity实用程序,如其他答案所示。


son*_*yao 29

你需要停下模板参数推导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;
}
Run Code Online (Sandbox Code Playgroud)

生活

顺便说一句:如果您的编译器不支持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;
Run Code Online (Sandbox Code Playgroud)

  • 这个答案应该清楚地表明这是C ++ 20功能,这是2019年,并且没有一个主要的现存编译器完全支持为C ++ 20吹捧的功能。 (4认同)