我很惊讶类型衰减在SO或其他地方没有得到很好的解释,也许我没有使用正确的术语进行搜索,或者我可能没有正确理解整个事情。我的问题是:它是什么,它是如何(为什么)到达那里以及它的规则是什么?
如果你想知道我为什么问,下面是我的啜泣类型的衰变故事(不是问题的主题):
我最近在努力学习一些简单的模板,我想做这样的事情:
template <class FunObj>
double DoStuff(FunObj fob) // note that this returns double, not FunObj, as e.g. std::for_each() does
{ /* ... */ }
struct MyFunObj {
mutable size_t num_invoked; // collect usage statistics
MyFunObj()
:num_invoked(0)
{}
bool operator ()(double some_arg) const
{
++ num_invoked;
return sin(some_arg) < .5;
}
};
这很好,有一个期望函数对象的模板函数和一个函数对象。该函数被设计为不返回函数对象的状态(正如类似函数经常做的那样;它返回了一些复杂计算的结果),所以我认为我会把它专门用于引用物体。但类型衰减阻碍了(或者至少是我对它的理解):
MyFunObj fob;
DoStuff(fob); // passed by value, usage statistics are lost (no surprise here)
MyFunObj &ref = fob;
DoStuff(ref); // MyFunObj& decays to MyFunObj, usage statistics are lost
DoStuff(static_cast<MyFunObj&>(fob)); // again, hampered by type decay
我知道如何解决这个问题,所以请不要回复。我只对这种类型的衰变感兴趣,这只是作为我的问题的动机/一个说明性的例子。如果你愿意,你可以发表一些讨厌我使用mutable
。
答案 0 :(得分:10)
我真的不认为你的问题显示了类型衰减的例子。术语&#34;衰变&#34;通常用于指代标准的函数到指针,数组到指针和左值到右值的转换。您要点击的是模板参数推断的规则。
问题是模板参数推断基于类型,不是基于值类别。示例中ref
的类型是{{1}并且它是该类型的左值(BTW,与MyFunObj
完全相同)。由于演绎适用于类型,fob
会推导到FunObj
的类型,这确实是ref
。
在C ++ 11之前,没有办法推断出引用类型。 C ++ 11用&#34;转发引用改变了这一点。&#34;这些引入了一种特殊情况,其中将类型MyFunObj
的左值传递给声明为U
的函数参数(其中T&&
是函数模板的模板参数)使用T
作为演绎的类型而不是U&
。但这是一个特殊的规则,一个例外。通常,价值类别不会在类型扣除中发挥作用。