xml*_*lmx 17 c++ templates overloading c++11 forwarding-reference
#include <vector>
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(&T::size)>
void f3(T&&)
{}
int main()
{
vector<int> coll;
f1(coll); // ok
f2(coll); // ok
f3(coll); // error : no matching function for call to 'f3'
}
Run Code Online (Sandbox Code Playgroud)
main.cpp(21,6):注意:候选模板被忽略:替换失败[with
T=>std::vector<int, std::allocator<int> > &]:类型'std::vector<int, std::allocator<int> > &'在'::' 之前不能使用,因为它没有成员
void f3(T&&)
我的编译器是clang 4.0.
令我惊讶的是,f3(coll)失败了,f1(coll)而且f2(coll)都很好.
为什么转发引用在这种情况下不起作用?
Whi*_*TiM 21
因为T推断为引用类型,所以需要使用std::remove_reference
template<typename T, typename = decltype(&std::remove_reference_t<T>::size)>
void f3(T&&)
{}
Run Code Online (Sandbox Code Playgroud)
完整示例:
#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
}
Run Code Online (Sandbox Code Playgroud)
通常,在使用转发引用时,类型修改实用程序非常方便; 主要是因为转发参考保留了价值类别和cv资格.
例1:
下面的代码无法编译,因为T推断为,std::vector<int>&并且您不能将非const引用绑定到临时的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);
}
Run Code Online (Sandbox Code Playgroud)您可以删除引用以使其工作:
#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);
}
Run Code Online (Sandbox Code Playgroud)示例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);
}
Run Code Online (Sandbox Code Playgroud)我们可以cv从removed-reference的类型中删除限定符.
#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);
}
Run Code Online (Sandbox Code Playgroud)我们可以继续,因为我们可以通过嵌套将它们组合成一行,例如:==> using D = std::remove_cv_t<std::remove_reference_t<T>>.
虽然有std::decay这确实是强大的,短期的这种"二合一踢"(但有时你想少一点的是什么std::decay呢).