I was surprised the type decay is not explained very well on SO or elsewhere, maybe I did not search using the correct terms or maybe I'm not understanding the whole thing correctly. My question is: what it is, how (why) did it get there and what are the rules of it?
If you are wondering why I'm asking, below is my sob type decay story (not the subject of the question, though):
I was recently struggling with some simple templates and I wanted to do something like this:
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;
}
};
This is all nice, there is a template function expecting a function object, and a function object. The function was designed to not return the state of the function object (as similar functions often do; it was returning a result of some intricate computation instead), so I thought I would specialize it for a reference to the object. But the type decay gets in the way (or at least that is my understanding of it):
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
I know how to solve this, so please do not reply how. I'm only interested in type decay as such and this is here only as a motivation of my question / an illustrative example. If you like, you can post some hate for my use of mutable
.
Type decay would be how an array can decay into a pointer (i.e. char[] into char* ). – JBL.
C++ProgrammingServer Side Programming. The loss of type and dimensions of an array is known as array decay. It occurs when we pass the array into a function by pointer or value. First address is sent to the array which is a pointer. That is why, the size of array is not the original one.
From Code 1, whenever arrays are passed as the arguments to functions, they are always passed by using the 'Pass by reference' mechanism. Because of this, they will decay into pointers in the function parameters.
I don't really think your question shows an example of type decay. The term "decay" is commonly used to refer to the standard function-to-pointer, array-to-pointer and lvalue-to-rvalue conversions. What you're hitting are the rules for template argument deduction.
The thing is that template argument deduction is based on types, not on value categories. The type of ref
in your example is MyFunObj
, and it's an lvalue of that type (BTW, exactly the same holds for fob
). Since deduction works on types, FunObj
is deduced to the type of ref
, which is indeed MyFunObj
.
Before C++11, there was no way to deduce a reference type. C++11 changed this with "forwarding references." These have introduced a special case where passing an lvalue of type U
to a function parameter declared as T&&
(where T
is a template parameter of the function template) uses U&
as the type for deduction instead of U
. But that's a special rule, an exception. Normally, value categories don't play a role in type deduction.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With