How can I use decltype to get the type of a reference?

4.5k views Asked by At

I'm working on some code using decltype in CodeGear RAD Studio. I've tried the naive solution, which looks not unlike this:

int main(int, char**) {
    int i;
    int &ir = i;
    decltype((ir)) ir_clone = ir;
}

Of course, this fails to compile: Internal Compiler Error. I rather suspect that there is nothing particularly wrong with that code and there is a compiler bug regarding reference expressions. (Incidentally, g++ has no problem with the code and compiles it fine.) That doesn't help solve the problem, however, as the platform is non-negotiable.

If, above, I had written

    decltype(ir) ir_clone = ir; /* No extra parens */

it compiles and works as expected. However, the problem doesn't end there, since that doesn't correctly compute constness from the environment. In particular:

struct S { int i; } s;
const S* p = &s;
decltype(p->i)   i0 = s.i; /* i0 is an int */
decltype((p->i)) i1 = s.i; /* i1 is a const int& */

If I don't use the parens to make the argument an expression, I lose the constness of the argument, which I need.

Another tool I can use is simple templates, like so:

template<class T> struct unref     { typedef T type; }
template<class T> struct unref<T&> { typedef T type; }

That lets me strip away the reference portion of a type, by using unref<int&>::type.

What I can't seem to figure out is how to put all these tools together to get a successful expression for the type I need. For one of things I need, I'm working on a generalized macro that does 'foreach'. (Yes, I know Boost does it better.) It needs to handle the following scenarios:

(vector<int>) vi          => vector<int>
(vector<int>&)vir         => vector<int>
(const vector<int>) cvi   => const vector<int>
(const vector<int>&)cvir  => const vector<int>
(const P*) cp->vi         => const vector<int>
(P*) p->vi                => vector<int>

So far, my simple attempts fail:

unref<decltype(cp->vi)>   /* is vector<int>, not what I need. */
unref<decltype((cp->vi))> /* is const vector<int>, which is right. */

unref<decltype(vir)>      /* is vector<int>, which is right. */
unref<decltype((vir))>    /* Internal Compiler Error, which is a headache. */

Any ideas to get me on the right track? Hopefully there's just something simple I'm missing. Maybe I'm attacking the problem from the wrong angle.

2

There are 2 answers

2
GManNickG On BEST ANSWER

Try making a different, more complex expression that results in the same type that you want, such as:

decltype((void(), ir))

I couldn't tell you why it fixes it, but sometimes a different expression will do the trick.

0
Aharon Abramson On

You can use std::remove_reference (see http://en.cppreference.com/w/cpp/types/remove_reference).