因为T
被推导出为引用类型,所以需要使用std::remove_reference
template<typename T, typename = decltype(&std::remove_reference_t<T>::size)>
void f3(T&&)
{}
完整示例:
#include <vector>
#include <type_traits>
using namespace std;
template<typename T, typename = decltype(&T::size)>
void f1(T)
{}
template<typename T, typename = decltype(&T::size)>
void f2(T&)
{}
template<typename T, typename = decltype(&std::remove_reference_t<T>::size)>
void f3(T&&)
{}
int main()
{
vector<int> coll;
f1(coll); // ok
f2(coll); // ok
f3(coll); // ok
}
演示
通常,在使用Forwarding References时,类型修改实用程序非常方便;主要是因为转发引用保留了值类别和cv
限定。
示例 1:
下面的代码无法编译,因为T
推断为std::vector<int>&
并且您不能将非常量引用绑定到临时 in foo
:
#include <vector>
template<typename T>
void foo(T&&){
T nV = {3, 5, 6};
}
int main(){
std::vector<int> Vec{1, 2 ,3, 4};
foo(Vec);
}
您可以删除引用以使其正常工作:
#include <vector>
template<typename T>
void foo(T&&){
using RemovedReferenceT = std::remove_reference_t<T>;
RemovedReferenceT nV = {3, 5, 6};
}
int main(){
std::vector<int> Vec{1, 2 ,3, 4};
foo(Vec);
}
示例 2(基于示例 1):
简单地删除引用在下面的代码中是行不通的,因为推导的类型带有一个const
限定,(又名,T
推导为const std::vector<int>&
)新类型RemoveReferenceT
是const std::vector<int>
:
#include <vector>
template<typename T>
void foo(T&&){
using RemovedReferenceT = std::remove_reference_t<T>;
RemovedReferenceT nV = {3, 5, 6};
nV[2] = 7; //woopsie
}
int main(){
const std::vector<int> Vec{1, 2 ,3, 4}; //note the const
foo(Vec);
}
我们可以从removed-reference 的类型中删除cv
限定符。
#include <vector>
template<typename T>
void foo(T&&){
using RRT = std::remove_reference_t<T>;
using Removed_CV_of_RRT = std::remove_cv_t<RRT>;
Removed_CV_of_RRT nV = {3, 5, 6};
nV[2] = 7;
}
int main(){
const std::vector<int> Vec{1, 2 ,3, 4};
foo(Vec);
}
我们可以继续下去,当然,我们可以通过嵌套将它们组合在一行中,例如: ==> using D = std::remove_cv_t<std::remove_reference_t<T>>
。
尽管对于这种“组合踢”来说std::decay
,这确实非常强大且简短(但有时您想要的功能少一点)std::decay
。