Unable to use declval in typeid for TDM-GCC
Asked Answered
S

1

6

Compiler: TDM-GCC-5.1.0 (SJLJ unwinding)

I was playing around with declval and I noticed that I was unable to use it in a context where it should work: as an argument to typeid().

In the following code, I use declval for one of it's primary use cases: to obtain the return type of a method without going through an instance. The error I get is the static_assert message of declval, but that should be impossible because typeid() doesn't evaluate it's argument in this case:

#include <typeinfo>
#include <utility>

struct Foo
{
    int func();
};

int main()
{
    typeid(std::declval<Foo>().func());
}

This doesn't compile for me (when compiled with -std=c++14). My only guess is that either I've found a compiler bug, or I've done something obviously wrong and I can't see it. If it is the latter, my apologies.

EDIT: Thanks to ildjarn for helping me out, the solution is to use decltype, so the last line of code becomes:

typeid(decltype(std::declval<Foo>().func()));

and this works nicely. However, now my question becomes: how come? Both typeid() and decltype() are unevaluated contexts, so I'm not sure what the difference is.

Stanwinn answered 25/8, 2016 at 22:37 Comment(9)
Try typeid(decltype(std::declval<Foo>().func()));Instate
Ah, that works! Wonder why that is though...Stanwinn
From cppreference: "If expression is not a glvalue expression of polymorphic type, typeid does not evaluate the expression[.]". I'm thinking compiler bug.Veiled
@Veiled : Yup – "If expression is not a glvalue expression of polymorphic type, typeid does not evaluate the expression, and the std::type_info object it identifies represents the static type of the expression." Exactly as does decltype, which fixes it.Instate
@Instate I'm not sure what you're saying. Using decltype calls the other version of typeid (labeled "(1)" in cppreference). But "version 2" should also work as-is, since it does not evaluate its argument.Veiled
@Veiled : That's exactly what I'm saying – using decltype, which works, should be semantically identical to "version 2", which doesn't. "Yup" meaning "yup, definitely compiler bug."Instate
@ildjarn, so it IS a bug. Well, I think I'll answer the question nowStanwinn
@Instate my bad ! Thanks for the clarification :)Veiled
Do note that there are situations where typeid will evaluate its parameter by design, namely when used with polymorphic types. It may be best to wrap declval in decltype whenever using typeid, to guarantee an unevaluated context.Janeanjaneczka
S
4

It's a compiler bug.

The solution around it is to use decltype() around the expression. Both decltype() and typeid() (in this case of a non-polymorphic-glvalue expression) are unevaluated contexts, which shouldn't make a difference, which is what makes this a bug. Using decltype() here acts as a sort of "unevaluated context buffer", and somehow typeid() likes this better.

Well, time to contact TDM about this. This bug isn't TDM's issue, it's a vanilla bug (thanks ildjarn).

Stanwinn answered 25/8, 2016 at 23:10 Comment(1)
This bug repros on upstream GCC, albeit with a different manifestation. It would appear that the compiler is trying to evaluate std::declval thus causing an error before it's decided it's operating in an unevaluated context, which wouldn't have caused the error. (Ahh, I love C++.) In any case, I don't think TDM has any part to play here.Instate

© 2022 - 2025 — McMap. All rights reserved.