以下的内容是最新的c++0x标准当中的,其中vs2010是符合这个标准的TypeName&&表示右值引用类型:
为了判断一个表达式是左值还是右值,第一个想法是写函数来判断,函数不能模板特化,因此通过重载来确定是不错的方法:
第一个函数接受非const左值:
template
void GetValType(T&)
{
cout << "Not a Right Value, a T" << endl;
}
第二个函数接受const左值:
template
void GetValType(const T&)
{
cout << "Not a Right Value, a const T" << endl;
}
第三个函数接受非const右值:
template
void GetValType(T&&)
{
cout << "A Right Value" << endl;
}
第四个函数接受const右值:
template
void GetValType(const T&&)
{
cout << "A Const Right Value" << endl;
}
为了获得一个常数右值,定义一个函数:
const int RetAnIntLVal(){return 0;}
那么对于以下的语句:
GetValType(1 + 1);
const int ia = 0;
GetValType(ia);
GetValType(RetAnIntLVal());
输出的结果是:
A Nonconst Right Value
A Const Left Value
A Const Right Value
但是对于以下的语句
int ib = 0;
GetValType(ib);
却得到了编译错误:
error C2668: 'GetValType' : ambiguous call to overloaded function
更详细的编译错误为:
could be 'void GetValType
with
[
T=int &
]
'void GetValType
with
[
T=int
]
while trying to match the argument list '(int)'
就是说一个int的值可以匹配到(第三个函数)
void GetValType(int& &&)
也可以匹配到(第一个函数)
void GetValType(int&)
其实当初想的是只匹配上述两个的后者,但是前者为什么会也能够匹配到呢,而且同样是精确匹配(重载无法选择更好的,后者又明显是精确匹配),答案就出在了下表中,
the reference collapsing rules fortemplate argument type deduction:
Expanded type | Collapsed type |
T& & | T& |
T& && | T& |
T&& & | T& |
T&& && | T&& |
就是说左边的类型会坍塌成为右边的类型,恰好第二个坍塌就是前一个函数的情况,那么这个问题如何解决呢?
考虑如下一个外层函数:
template
void OuterGet(T&& temp)
{//forward是完美转发,将转发temp的真实类型给另一个函数作为实参
GetValType
}
但是这样的函数仍然是错误的,给出的编译错误令人震惊:
当OuterGet函数以T=int &绑定时,那么对于GetValType来说T = int & &&即int &这样按理说模板函数1就会实例化成为GetValType(int&),这是最贴切的,但是编译器给出的答案是它把函数2和函数4实例化成GetValType(int)这样就ambiguous了,然后报错.我具体也不知道是怎么回事,苦思一日之后编了一个理由来解释:函数模板类型在显示指定的时候不支持类型坍塌(Type Collapse),而是会出现一些莫名奇妙的结果注1.
既然函数类型不支持,那么模板类型定然是支持的,这样也符合表给出的意思:仅仅支持在模板实参推导中,函数实参推导就不支持了.
于是就有了以下的实现代码:
#include <iostream>
using namespace std;
template<class T> struct Help;
template<class T>
struct Help<T&>
{
static void GetValType(T&)
{
cout << "A Nonconst Left Value" << endl;
}
};
template<class T>
struct Help<const T&>
{
static void GetValType(const T&)
{
cout << "A Const Left Value" << endl;
}
};
template<class T>
struct Help<T&&>
{
static void GetValType(T&&)
{
cout << "A Nonconst Right Value" << endl;
}
};
template<class T>
struct Help<const T&&>
{
static void GetValType(const T&&)
{
cout << "A Const Right Value" << endl;
}
};
template<class T>
void Deliver(T&& temp)
{
Help<T&&>::GetValType(forward<T>(temp));
}
int main()
{
int ia = 0;
Deliver(ia);
const int ib = 0;
Deliver(ib);
Deliver(0);
Deliver(RetAnIntLVal());
}
以上代码就可以完成正确的任务.
注1见以后随笔
原文链接: https://www.cnblogs.com/observer/archive/2011/08/31/2161164.html
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/31523
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!