9

Consider the following example. Somewhere in my code is a name x. I have no idea if x is a type or an object (it could be both). Is there any way to get the type of x, i.e., x itself if x is a type or decltype(x) if x is an object?

I tried doing something as trivial as

decltype(int)

but this yields an error, since int is not an expression. Is there any substitute way to do this?

I would like something like:

typedef int l;
mydecltype(l) x; // int x;
mydecltype(x) y; // int y;

How can I get this done?

Přemysl Šťastný
  • 1,676
  • 2
  • 18
  • 39
Matteo Monti
  • 8,362
  • 19
  • 68
  • 114
  • 7
    How did you end up with a name for which you don't know whether it's a type or an object? Where does this name come from? The problem statement doesn't make sense to me; feels like an [XY problem](http://xyproblem.info/). – Igor Tandetnik Jul 19 '16 at 15:02
  • I wanted to add more background but the explanation would be extremely lengthy. I am working with preprocessing directives and initialization lists on classes that inherit from other classes. In an initialization list, types and member names have the same format and I cannot get to distinguish them from the syntax. – Matteo Monti Jul 19 '16 at 15:04
  • It is definitely an XY problem, but I wouldn't be able to describe the whole problem, as it not just as simple as "I need a filename extension" :) – Matteo Monti Jul 19 '16 at 15:06
  • @akappa: He probably can't. It's bad design, obviously, but if it's some old project, his job description might be to do it anyhow. – Aziuth Jul 19 '16 at 15:23
  • @akappa Might be. Now, let's play this little game: You are an employee and your boss tells you to do something stupid. What exactly are you going to do? "Nah, I won't do it, that's stupid!"? Keep that in mind when answering questions. – Aziuth Jul 21 '16 at 08:32

1 Answers1

28
namespace detail_typeOrName {
    struct probe {
        template <class T>
        operator T() const;
    };

    template <class T>
    T operator * (T const &, probe);

    probe operator *(probe);
}

#define mydecltype(x) decltype((x) * detail_typeOrName::probe{})

In this code, (x) * detail_typeOrName::probe{} can be parsed two ways:

  • If x is a variable, this is x multiplied by the instance of probe.
  • If x is a type, this is the instance of probe dereferenced and cast to X.

By carefully overloading operators, both interpretations are made valid, and both return the type we seek.

Live on Coliru

Quentin
  • 62,093
  • 7
  • 131
  • 191
  • Man, you gave me goosebumps. – Matteo Monti Jul 19 '16 at 15:23
  • That's insanely clever! I'd never thought of abusing the dereference AND the cast operator in such a way. Hopefully, this won't break in the future and so have to be dealt by some unlucky, clueless maintainer... – akappa Jul 19 '16 at 16:08