Hi all,
At
30:05 on day 215, we hit a compile error owing to the behavior of decltype(e).
For reference, the rule is
here.
Basically: the idea is that if you give it a variable name (without extra parentheses), you just get the type of that variable. Otherwise, you get the type of the expression, except that in the case where the expression is an lvalue, the compiler adds '&' to reflect the lvalue-ness of the expression.
The original proposals for decltype (from 2006) motivate this behavior, but the use cases tend to involve templates exclusively.
Since we tend to avoid templates on HMH, we just want a way to remove the top-level ref. Unfortunately, the only way I know to do that is with a template. But it's a fairly small & isolated use and does not involve any libraries.
Here it is:
| template<class T>struct remove_ref { typedef T type; };
template<class T>struct remove_ref<T&> { typedef T type; };
template<class T>struct remove_ref<T&&>{ typedef T type; };
#define etype(e) remove_ref<decltype(e)>::type
|
And here's a sample use:
| int r[10];
int x;
int y;
etype(r[0]) z1 = 42; // ok (z1 is of type remove_ref<T&>::type,
// a.k.a. int)
|
For completeness, here's the error condition we're trying to avoid:
| decltype(r[0]) z2 = 42; // error (cannot initialize 'int&'
// with an rvalue)
|
One more thing: if you happen to be doing some metaprogramming (or other tasks that required you to write your own C parser from scratch), you probably won't want to bother with modifying your parser to support templates just for this. In that case, #ifdef it:
| #if WE_DISLIKE_TEMPLATES
#define etype(e) etype(e) // You'll want to teach
// your parser about this.
#else
template<class T>struct remove_ref { typedef T type; };
template<class T>struct remove_ref<T&> { typedef T type; };
template<class T>struct remove_ref<T&&>{ typedef T type; };
#define etype(e) remove_ref<decltype(e)>::type
#endif
|