369

This is a somewhat bizarre question. My objectives are to understand the language design decision and to identify the possibilities of reflection in C++.

  1. Why C++ language committee did not go towards implementing reflection in the language? Is reflection too difficult in a language that does not run on a virtual machine (like java)?

  2. If one were to implement reflection for C++, what will be the challenges?

I guess the uses of reflection are well-known: editors can be more easily written, program code will be smaller, mocks can be generated for unit tests and so on. But it would be great if you could comment on uses of reflection too.

amit kumar
  • 20,438
  • 23
  • 90
  • 126
  • 3
    Because I think adding reflection to C++ would be the greased pole to insanity! ;-) – KWallace Jul 17 '22 at 01:51
  • I agree with KWallace. Other languages solve this issue so nicely: https://stackoverflow.com/questions/24559016/delphi-use-reflection-in-a-class-procedure-for-the-getting-dynamic-class-type – Gabriel Dec 28 '22 at 17:55

15 Answers15

664

There are several problems with reflection in C++.

  • It's a lot of work to add, and the C++ committee is fairly conservative, and don't spend time on radical new features unless they're sure it'll pay off. (A suggestion for adding a module system similar to .NET assemblies has been made, and while I think there's general consensus that it'd be nice to have, it's not their top priority at the moment, and has been pushed back until well after C++0x. The motivation for this feature is to get rid of the #include system, but it would also enable at least some metadata).

  • You don't pay for what you don't use. That's one of the must basic design philosophies underlying C++. Why should my code carry around metadata if I may never need it? Moreover, the addition of metadata may inhibit the compiler from optimizing. Why should I pay that cost in my code if I may never need that metadata?

  • Which leads us to another big point: C++ makes very few guarantees about the compiled code. The compiler is allowed to do pretty much anything it likes, as long as the resulting functionality is what is expected. For example, your classes aren't required to actually be there. The compiler can optimize them away, inline everything they do, and it frequently does just that, because even simple template code tends to create quite a few template instantiations. The C++ standard library relies on this aggressive optimization. Functors are only performant if the overhead of instantiating and destructing the object can be optimized away. operator[] on a vector is only comparable to raw array indexing in performance because the entire operator can be inlined and thus removed entirely from the compiled code. C# and Java make a lot of guarantees about the output of the compiler. If I define a class in C#, then that class will exist in the resulting assembly. Even if I never use it. Even if all calls to its member functions could be inlined. The class has to be there, so that reflection can find it. Part of this is alleviated by C# compiling to bytecode, which means that the JIT compiler can remove class definitions and inline functions if it likes, even if the initial C# compiler can't. In C++, you only have one compiler, and it has to output efficient code. If you were allowed to inspect the metadata of a C++ executable, you'd expect to see every class it defined, which means that the compiler would have to preserve all the defined classes, even if they're not necessary.

  • And then there are templates. Templates in C++ are nothing like generics in other languages. Every template instantiation creates a new type. std::vector<int> is a completely separate class from std::vector<float>. That adds up to a lot of different types in a entire program. What should our reflection see? The template std::vector? But how can it, since that's a source-code construct, which has no meaning at runtime? It'd have to see the separate classes std::vector<int> and std::vector<float>. And std::vector<int>::iterator and std::vector<float>::iterator, same for const_iterator and so on. And once you step into template metaprogramming, you quickly end up instantiating hundreds of templates, all of which get inlined and removed again by the compiler. They have no meaning, except as part of a compile-time metaprogram. Should all these hundreds of classes be visible to reflection? They'd have to, because otherwise our reflection would be useless, if it doesn't even guarantee that the classes I defined will actually be there. And a side problem is that the template class doesn't exist until it is instantiated. Imagine a program which uses std::vector<int>. Should our reflection system be able to see std::vector<int>::iterator? On one hand, you'd certainly expect so. It's an important class, and it's defined in terms of std::vector<int>, which does exist in the metadata. On the other hand, if the program never actually uses this iterator class template, its type will never have been instantiated, and so the compiler won't have generated the class in the first place. And it's too late to create it at runtime, since it requires access to the source code.

  • And finally, reflection isn't quite as vital in C++ as it is in C#. The reason is again, template metaprogramming. It can't solve everything, but for many cases where you'd otherwise resort to reflection, it's possible to write a metaprogram which does the same thing at compile-time. boost::type_traits is a simple example. You want to know about type T? Check its type_traits. In C#, you'd have to fish around after its type using reflection. Reflection would still be useful for some things (the main use I can see, which metaprogramming can't easily replace, is for autogenerated serialization code), but it would carry some significant costs for C++, and it's just not necessary as often as it is in other languages.

Edit: In response to comments:

cdleary: Yes, debug symbols do something similar, in that they store metadata about the types used in the executable. But they also suffer from the problems I described. If you've ever tried debugging a release build, you'll know what I mean. There are large logical gaps where you created a class in the source code, which has gotten inlined away in the final code. If you were to use reflection for anything useful, you'd need it to be more reliable and consistent. As it is, types would be vanishing and disappearing almost every time you compile. You change a tiny little detail, and the compiler decides to change which types get inlined and which ones don't, as a response. How do you extract anything useful from that, when you're not even guaranteed that the most relevant types will be represented in your metadata? The type you were looking for may have been there in the last build, but now it's gone. And tomorrow, someone will check in a small innocent change to a small innocent function, which makes the type just big enough that it won't get completely inlined, so it'll be back again. That's still useful for debug symbols, but not much more than that. I'd hate trying to generate serialization code for a class under those terms.

Evan Teran: Of course these issues could be resolved. But that falls back to my point #1. It'd take a lot of work, and the C++ committee has plenty of things they feel is more important. Is the benefit of getting some limited reflection (and it would be limited) in C++ really big enough to justify focusing on that at the expense of other features? Is there really a huge benefit in adding features the core language which can already (mostly) be done through libraries and preprocessors like QT's? Perhaps, but the need is a lot less urgent than if such libraries didn't exist. For your specific suggestions though, I believe disallowing it on templates would make it completely useless. You'd be unable to use reflection on the standard library, for example. What kind of reflection wouldn't let you see a std::vector? Templates are a huge part of C++. A feature that doesn't work on templates is basically useless.

But you're right, some form of reflection could be implemented. But it'd be a major change in the language. As it is now, types are exclusively a compile-time construct. They exist for the benefit of the compiler, and nothing else. Once the code has been compiled, there are no classes. If you stretch yourself, you could argue that functions still exist, but really, all there is is a bunch of jump assembler instructions, and a lot of stack push/pop's. There's not much to go on, when adding such metadata.

But like I said, there is a proposal for changes to the compilation model, adding self-contained modules, storing metadata for select types, allowing other modules to reference them without having to mess with #includes. That's a good start, and to be honest, I'm surprised the standard committee didn't just throw the proposal out for being too big a change. So perhaps in 5-10 years? :)

Ziezi
  • 6,375
  • 3
  • 39
  • 49
jalf
  • 243,077
  • 51
  • 345
  • 550
  • 2
    Don't most of these issues already have to be solved by debug symbols? Not that it would be performant (because of the inlining and optimization you mentioned), but you could allow for the *possibility* of reflection by doing whatever debug symbols do. – cdleary Dec 11 '08 at 21:03
  • 1
    fantastic answer, though I believe all the technical issues could be resolved. You could make it a keyword which enables reflection on a class. you could get compile time errors if reflection is used on a non keyworded class. Also you could disallow it being combined with templates. – Evan Teran Dec 11 '08 at 21:12
  • Finally, there could be a rule that classes which enable reflection must not be optimized away to nothing. So it would add an expense, *if* you asked for it. – Evan Teran Dec 11 '08 at 21:13
  • These rules I mentioned pretty much cover what QT's MOC system does. – Evan Teran Dec 11 '08 at 21:13
  • Added responses to your comments in the main post. :) But in short, yeah, debug symbols do a bit of the same, on a small scale, and of course the technical issues *could* be resolved. – jalf Dec 11 '08 at 22:09
  • 1
    "As it is now, types are exclusively a compile-time construct" - Generally this answer is good for getting across the intended spirit of C++ and the reason why RTTI is a last resort, but it IS there in the standard, and it already addresses some of your issues - e.g. interaction with templates. – Daniel Earwicker Dec 12 '08 at 07:30
  • +1 - but like earwicker commented, polymorphic types do end up having RTTI - and a limited form of reflection is possible using the native typeid operator - the answer would be even better if it touched upon that :) – Faisal Vali Sep 12 '09 at 22:56
  • 1
    Perhaps. I don't really consider RTTI reflection though. Reflection gives you information about a type. The best RTTI can do is tell you what type a value has. It doesn't say anything *about* the type. Apart from that, I don't want to edit my post, because it might get community-wikied. ;) – jalf Sep 12 '09 at 23:30
  • 3
    Another thing about your first point: as far as I know nobody's tried adding reflection to a C++ implementation. There's no good experience with it. The Committee is probably going to be reluctant to take the lead, particularly after `export` and `vector`. – David Thornley Nov 06 '09 at 17:04
  • One another point I'd like to add to your answer (great answer btw), is that even if one compiler decides to optimize in a certain way there is no guarantee that another compiler would do it in the exact same way, so you can't write portable code (portable for being compilable across compilers in different platforms that is). – Murali VP Nov 06 '09 at 17:12
  • Oh I just love the _You don't pay for what you don't use._ rule! Thanks for the thoughtful answer Jalf! – legends2k Apr 12 '10 at 14:07
  • Thank you. It always hurts me when people describe reflection as a glaring weakness in c++'s concept. Not that it doesn't have them, but reflection isn't among them – Anne Quinn Jan 02 '12 at 01:31
  • 22
    I agree that C++ should not have run time reflection. But compile time reflection has few of the above problems, and could be used for someone to build run time reflection on particular classes if they choose to. Being able to access the type and name and features of the nth method and nth parent of a class via a template? And get the number of such at compile time? Would make CRTP based automatic reflection doable, while nobody is paying for what they aren't using. – Yakk - Adam Nevraumont Dec 12 '12 at 22:41
  • 21
    Your third point is in many respects the most important: C++ is intended to be suitable for writing standalone code on platforms where memory costs money; if eliminating some unused code would allow a program to fit in a microcontroller that costs $2.00, rather than one that costs $2.50, and if the code is going in 1,000,000 units, eliminating that code can save $500,000. Without reflection, static analysis can often identify 90%+ of unreachable code; if Reflection is allowed, anything that can be reached via Reflection must be presumed reachable, even if 90% of it isn't. – supercat Mar 04 '13 at 20:55
  • 3
    there is definitely something that can be improved easily by the comitee, it is to finally say black on white that `typeinfo`'s `name()` function MUST return the name that was typed in by the programmer and not something undefined. And give us a stringifier for enumerators as well. This is actually crucial for serialization/deserialization, helping in making factories etc. – v.oddou Apr 18 '13 at 02:13
  • 1
    @v.oddou: write proposals for those features, and submit them to the committee. :) Your pet features won't add themselves. Someone needs to propose them, and write the specification for them. – jalf Apr 18 '13 at 12:30
  • @jalf 6 years and counting... is there any updates on this subject? – RSFalcon7 Jan 30 '14 at 19:18
  • 1
    @RSFalcon7 not really. There's been some talk of adding special "rich pointers" to the language, which allow you to get some reflection-like information about the types they point to. But I haven't read the proposal in detail, or kept up with how far it's gotten. – jalf Jan 31 '14 at 11:47
  • This is a very good answer, but I feel there's more recent info to add which may be of interest. This year at CPPCon, David Sankel (a Bloomberg architect on the C++ committee) was on a panel discussing the status of current proposals for static reflection in C++. He gave the impression that although it's at an early phase, proposal P0385 (http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2016/p0385r0.pdf) is being taken seriously as a possibility for c++20. He was careful not to promise anything, but seemed very hopeful :) – stett Sep 24 '16 at 21:53
  • It ended up being 12 years, but wow, that was an impressive prediction. – Baruch Feb 20 '20 at 14:36
  • @supercat Um no. That is not the most important thing about C++. – user253751 Oct 09 '20 at 16:58
  • @user253751: I said *in many respects*, the third point was among the most important, and I gave an *example* of why reflection can impose real-world monetary costs. – supercat Oct 09 '20 at 17:05
  • 1
    If you have a class with no methods, do you pay for an empty vtable? – ATL_DEV Feb 27 '21 at 23:33
  • 1
    Surprisingly, this answer has gone out of date. C# no longer guarantees the class will be there even if nothing calls it; the last stage linker of the final executable can remove it. – Joshua Mar 20 '21 at 04:36
46

Reflection requires some metadata about types to be stored somewhere that can be queried. Since C++ compiles to native machine code and undergoes heavy changes due to optimization, high level view of the application is pretty much lost in the process of compilation, consequently, it won't be possible to query them at run time. Java and .NET use a very high level representation in the binary code for virtual machines making this level of reflection possible. In some C++ implementations, however, there is something called Run Time Type Information (RTTI) which can be considered a stripped down version of reflection.

Mehrdad Afshari
  • 414,610
  • 91
  • 852
  • 789
  • 16
    RTTI is in the C++ standard. – Daniel Earwicker Dec 12 '08 at 07:27
  • 1
    But not all C++ implementations are standard. I've seen implementations that don't support RTTI. – Mehrdad Afshari Dec 14 '08 at 09:44
  • 5
    And most implementations that do support RTTI also support turning it off via compiler options. – Michael Kohne Nov 06 '09 at 20:12
  • I liked Delphi's reflection (and full RTTI support): https://www.embarcaderoacademy.com/p/reflection-and-modern-rtti-in-delphi https://stackoverflow.com/questions/24559016/delphi-use-reflection-in-a-class-procedure-for-the-getting-dynamic-class-type – Gabriel Aug 31 '22 at 20:32
26

All languages should not try to incorporate every feature of every other language.

C++ is essentially a very, very sophisticated macro assembler. It is NOT (in a traditional sense) a high-level language like C#, Java, Objective-C, Smalltalk, etc.

It is good to have different tools for different jobs. If we only have hammers, all things are going to look like nails, etc. Having script languages is useful for some jobs, and reflective OO-languages (Java, Obj-C, C#) are useful for another class of jobs, and super-efficient bare-bones close-to-the-machine languages are useful for yet another class of jobs (C++, C, Assembler).

C++ does an amazing job of extending Assembler technology to incredible levels of complexity management, and abstractions to make programming larger, more complex tasks vastly more possible for human beings. But it is not necessarily a language that is the best suited for those who are approaching their problem from a strictly high-level perspective (Lisp, Smalltalk, Java, C#). If you need a language with those features to best implement a solution to your problems, then thank those who've created such languages for all of us to use!

But C++ is for those who, for whatever reason(s), need to have a strong correlation between their code and the underlying machine's operation. Whether its efficiency, or programming device drivers, or interaction with the lower-level OS services, or whatever, C++ is better suited to those tasks.

C#, Java, Objective-C all require a much larger, richer runtime system to support their execution. That runtime has to be delivered to the system in question - preinstalled to support the operation of your software. And that layer has to be maintained for various target systems, customized by SOME OTHER LANGUAGE to make it work on that platform. And that middle layer - that adaptive layer between the host OS and the your code - the runtime, is almost always written in a language like C or C++ where efficiency is #1, where understanding predictably the exact interaction between software and hardware can be well understood, and manipulated to maximum gain.

I love Smalltalk, Objective-C, and having a rich runtime system with reflection, meta-data, garbage collection, etc. Amazing code can be written to take advantage of these facilities! But that's simply a higher layer on the stack, a layer that must rest on lower layers, that themselves must ultimately sit upon the OS and the hardware. And we will always need a language that is best suited for building that layer: C++/C/Assembler.

Addendum: C++11/14 are continuing to expand C++ ability to support higher-level abstractions and systems. Threading, synchronization, precise memory models, more precise abstract machine definitions are enabling C++ developers to achieve many of the high-level abstractions that some of these high-level only languages used to have exclusive domain over, while continuing to provide close-to-metal performance and excellent predictability (i.e minimal runtime subsystems). Perhaps reflection facilities will be selectively enabled in a future revision of C++, for those who want it - or perhaps a library will provide such runtime services (maybe there is one now, or the beginnings of one in boost?).

Mordachai
  • 9,412
  • 6
  • 60
  • 112
  • Your point about the runtime of a language having to be compiled in another language is not true in the case of Objective-C, as it's runtime is written in C (which Objective-C is a superset of). – Richard J. Ross III May 07 '13 at 23:01
  • That's a distinction without a difference. What difference does it make, when in the end, the runtime subsystem that Objective-C uses is in fact not written in Objective-C, but rather in C? – Mordachai May 08 '13 at 21:32
  • Objective-C *is* C, and that is the point. Any C program is valid Objective-C, so its runtime system is infact compilable in its own language. – Richard J. Ross III May 09 '13 at 00:08
  • No, you cannot write an Objective-C program that compiles with a C compiler. They're not the same language. You cannot create Obj-C objects, you cannot use any of the runtime reflection services in C, etc. Just because Objective-C extends C doesn't make them the same language, or elide the need for a runtime subsystem to manage object lifetime and a type-query system, amongst other Objective-C features. – Mordachai May 09 '13 at 12:34
  • 3
    I'm sorry; but as long as you link it properly, you can compile an objective-c program in C, in fact I did it here: http://stackoverflow.com/a/10290255/427309. Your entire above statement is false. The runtime is fully accessible through C, and its one of the things that makes it such a powerful dynamic language. – Richard J. Ross III May 09 '13 at 12:43
  • Right... through C. C is required. A runtime exists for Objective-C. That runtime manages type-reflection, message passing, class objects, memory management, etc. I'm not sure what you're hung up on or think is incorrect. Without a runtime, Objective-C would not exist. C++ does not have a runtime (no dynamic type reflection, no memory management subsystem, no dynamic call binding beyond v-tables). That is a strong distinction, and it is baldly true. – Mordachai May 09 '13 at 14:59
  • Minor pedantic point: C++ and C both have a runtime system as well. The fact that you can embed the runtime into the binary or that they are generally smaller than the CLR/JVM is orthogonal to their existence (hello msvcrtXXX.dll!). You have to give up stuff like malloc to get true bare-bones binaries with no runtime (e.g.: see Rust's libcore support for writing boot loaders and kernels where you provide a couple of basic bootstrapping functions like malloc, or just avoid heap allocations entirely) – russbishop Jul 27 '14 at 02:46
  • Pedantic correction: msvcrt provides a "C runtime library", but is not itself core to the language. And at some point you get to degrees: where do you draw the line between a runtime and no runtime? I consider that C has no runtime - no garbage collection, no other threads managing anything, no automatic anything. No runtime type system. Nothing but malloc type interfaces which can be implemented as a facade over the OS, and hence, unless you consider the OS itself a "language runtime", then C has no runtime at all. – Mordachai Aug 06 '14 at 20:15
  • actually you can: the OS provides `mmap`, and in that sense it provides an allocator for languages. it also supports `sbrk` sometimes, and stack pages commitment, stack guarded page access signalisation, segmentation faults signalization, sigbus, pipe creation, thread creation, filber creation, context switches support, filesystem abstraction, pipes... its a huge runtime to me. – v.oddou Sep 01 '14 at 06:56
  • You cannot in all reasonableness consider the OS to be C++'s responsibility. Yes, C++ normally does sit on an OS for user-level applications. But what about embedded systems? How about device-drivers? The OS itself? All software exists in an ecosystem of some sort, but C++ does not require a running-chunk-of-code-to-execute-the-language-itself-or-to-support-its-core. No such thing is required by the language. C++ can be compiled and linked without any external references whatsoever). You can optionally use OS-services, and you can also use C-library or C++ libraries. Optional+You. – Mordachai Mar 16 '15 at 17:34
  • 1
    The "C runtime" is just a dynamic library containing the code for the C standard library. Same for the "C++ runtime". It's quite different from a runtime system like that of Objective-C. Also... while I suppose you could technically use the Objective-C runtime in C, that's still just a C program that uses the Objective-C runtime - you can't compile an actual Objective-C program in C. – celticminstrel Jul 24 '15 at 15:23
  • 2
    C++11 having a memory model + atomics makes it *more* like a portable assembler. Those aren't high-level things, they're *low* level things that C++ previously lacked portable support for. But the amount of UB in C++ if you do anything wrong makes it very unlike VM-based languages like Java, and also unlike any specific assembly language. e.g. signed-overflow is totally UB in C++ source *and the compiler can optimize based on that fact* even if compiling for lets say x86, but in asm on almost all platforms it will just wrap around. Modern C++ is very far from a portable assembly language. – Peter Cordes Aug 14 '18 at 10:20
12

If you really want to understand the design decisions surrounding C++, find a copy of the The Annotated C++ Reference Manual by Ellis and Stroustrup. It's NOT up to date with the latest standard, but it goes through the original standard and explains how things work and often, how they got that way.

Michael Kohne
  • 11,888
  • 3
  • 47
  • 79
11

Reflection for languages that have it is about how much of the source code the compiler is willing to leave in your object code to enable reflection, and how much analysis machinery is available to interpret that reflected information. Unless the compiler keeps all the source code around, reflection will be limited in its ability to analyze the available facts about the source code.

The C++ compiler doesn't keep anything around (well, ignoring RTTI), so you don't get reflection in the language. (Java and C# compilers only keep class, method names and return types around, so you get a little bit of reflection data, but you can't inspect expressions or program structure, and that means even in those "reflection-enabled" languages the information you can get is pretty sparse and consequently you really can't do much analysis).

But you can step outside the language and get full reflection capabilities. The answer to another stack overflow discussion on reflection in C discusses this.

Community
  • 1
  • 1
Ira Baxter
  • 93,541
  • 22
  • 172
  • 341
7

Reflection can be and has been implemented in c++ before.

It is not a native c++ feature because it have an heavy cost (memory and speed) that should'nt be set by default by the language - the language is "maximum performance by default" oriented.

As you shouldn't pay for what you don't need, and as yous say yourself it's needed more in editors than in other applications, then it should be implemented only where you need it, and not "forced" to all the code (you don't need reflection on all the data you'll work with in a editor or other similar application).

Klaim
  • 67,274
  • 36
  • 133
  • 188
  • 3
    and you don't ship symbols because it would allow your customers/competitors to look at your code... this is often considered a bad thing. – gbjbaanb Dec 11 '08 at 13:06
  • You're right, i didn't even though about the code exposition problem :) – Klaim Dec 11 '08 at 13:38
6

The reason C++ doesn't have reflection is that this would require the compilers to add symbol information to the object files, like what members a class type has, information about the members, about the functions and everything. This essentially would render include files useless, as information shipped by declarations would then be read from those object files (modules then). In C++, a type definition can occur multiple times in a program by including the respective headers (provided that all those definitions are the same), so it would have to be decided where to put the information about that type, just as to name one complication here. The aggressive optimization done by a C++ compiler, which can optimize out dozens of class template instantiations, is another strong point. It's possible, but as C++ is compatible to C, this would become an awkward combination.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • 1
    I don't understand how the compiler's aggressive optimization is a strong point. Can you elaborate? If the linker can remove duplicate inline-function definitions, what's the problem with duplicate reflection information? Isn't symbol information added to the object files anyway, for debuggers? – Rob Kennedy Dec 11 '08 at 13:39
  • 1
    The problem is that your reflection information may be invalid. If the compiler eliminates 80% of your class definitions, what is your reflection metadata going to say? In C# and Java, the language guarantees that if you define a class, it stays defined. C++ lets the compiler optimize it away. – jalf Dec 11 '08 at 13:47
  • 1
    @Rob, the optimizations are another point, not tied to the multiple classes complication. See @jalf's comment (and his answer) for what i meant. – Johannes Schaub - litb Aug 31 '09 at 12:25
  • 4
    If I instantiate reflect, then don't throw away any of T's information. This doesn't seem like an unsolvable problem. – Joseph Garvin Nov 28 '09 at 06:51
5

For the last 10 years, attempts are being made to add reflection to C++. The latest proposal is for and may or may not get in.

Unlike reflection in most languages, the plan for reflection is compile time reflection. So at compile time, you can reflect over struct members, function and method parameters and properties, enumeration values and names, etc.

You can then do limited reification, injecting information about what you reflected over to generate other types and code.

While this is a bit strange, what it means is that programs that do not use reflection do not pay a run time cost for it. It also is incredibly powerful.

The simplest example is that you can use it to implement runtime reflection.

struct Member {
  std::string_view name;
  std::any_ref value;
};

struct Reflectable {
  virtual std::span<Member> GetMembers() const = 0;
  virtual std::span<Member> GetMembers() = 0;
};

template<class D>
struct ImplReflectable:Reflectable {
  std::span<Member> GetMembers() const final;
  std::span<Member> GetMembers() final;
};
template<class D>
std::span<Member> ImplReflectable<D>::GetMembers() const {
  // compile time reflection code on D here
}
template<class D>
std::span<Member> ImplReflectable<D>::GetMembers() {
  // compile time reflection code on D here
}

you write the above once, and suddenly you for any type you want reflectable, you can just do this:

struct Point : ImplReflectable<Point> {
  int x, y;
};

and a reflection system is attached to Point.

The library that implements this runtime reflection can be as complex and powerful as you like. Each type would have to do a bit of work (like the above) to opt in, but doing so for a UI library (for example) isn't a serious problem. Types that don't opt in continue the C++ assumption of "don't pay for it if you aren't using it".

But that is only the start. One proposal, metaclasses, permits:

interface Reflectable {
  std::span<Member> GetMembers() const;
  std::span<Member> GetMembers();
};

you can have metaclasses, or functions that take types and return them. This allows you to define metaclasses of class, like "interface", written in-language. Now, interface is a bit of a toy, but you could write QObject or Reflectable or PolymorphicValueType or NetworkProtocol metaclasses that modify what your class definition means.

This may or may not get into . It continues to get better, but it also continues to get pushed back. There are multiple compile time reflection implementations out there for most major C++ compilers you can try. The syntax is in flux, as there are symbol-operator based reflection libraries, reflexpr based operator reflection libraries, some where the reflected data is types, others where it is constexpr objects and consteval functions.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
4

There are tons of cases for using reflection in C++ that cannot be adequately addressed using compile time constructs like template meta-programming.

N3340 proposes rich pointers as a way to introduce reflection in C++. Among other things it addresses the issue of not paying for a feature unless you use it.

pong
  • 115
  • 6
3

According to Alistair Cockburn, subtyping can't be guaranteed in a reflective environment.

Reflection is more relevant to latent typing systems. In C++, you know what type you've got and you know what you can do with it.

Nilone
  • 31
  • 1
  • More generally, the ability to check for the existence of a feature which does not exist without introducing Undefined Behavior makes it possible that adding that feature to a later version of a class will change the well-defined behavior of pre-existing programs, and will consequently make it impossible to guarantee that adding that feature won't "break" something. – supercat Mar 04 '13 at 20:42
  • @supercat Old comment, old question: but SFINAE made this problem exist in C++11. It wasn't well known 9 years ago I guess! – Yakk - Adam Nevraumont Apr 18 '22 at 04:36
  • @Yakk-AdamNevraumont: There is, or at least should be, a difference between making it impossible to guarantee that a construct will work for all combinations of components, versus breaking it for practical combinations of components, though some people seem to interpret a failure to mandate correct operation as an invitation to break things. – supercat Apr 18 '22 at 14:54
3

It is basically because it is an "optional extra". Many people choose C++ over languages like Java and C# so that they have more control over the compiler output, e.g. a smaller, and/or faster program.

If you choose to add reflection there are various solutions available.

Community
  • 1
  • 1
Nick
  • 27,566
  • 12
  • 60
  • 72
2

If C++ could have:

  • class member data for variable names, variable types, and the const modifier
  • a function arguments iterator (only position instead of name)
  • class member data for function names, return type, and the const modifier
  • list of parent classes (in the same order as defined)
  • data for template members and parent classes; the expanded template (meaning the actual type would be available for the reflection API and not the 'template information of how to get there')

That would be enough to create very easy to use libraries at the crux of the typeless data processing that is so prevalent in today's web and database applications (all the orms, messaging mechanisms, xml/json parsers, data serialization, etc).

For example, the basic information supported by the Q_PROPERTY macro (part of Qt Framework) http://qt.nokia.com/doc/4.5/properties.html expanded to cover class methods and e) - would be extraordinary beneficial to C++ and to the software community in general.

Certainly the reflection I am referring to would not cover the semantic meaning or more complex issues (like comments source code line numbers, data flow analysis, etc) - but neither do I think those are needed to be part of a language standard.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • @Vlad: Yes, if one adds features supporting reflection to the language, you get reflection in the language. This is only likely to happen if the language committee decrees it, and I think they have not as of 2011, and I doubt there will be another C++ standard out before 2020 AD. So, nice thought. In the meantime, if you want to make progress you'll likely have to step outside C++. – Ira Baxter Jun 19 '11 at 05:51
-1

Reflection could be optional, like a preprocessor directive. Something like

#pragma enable reflection

That way we can have the best of both worlds, with out this pragma libraries would be created without reflection (without any overheads as discussed), then it would be up the individual developer whether they want speed or ease of use.

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
user1401491
  • 441
  • 4
  • 4
-1

Reflection in C++ , I believe is crucially important if C++ is to be used as a language for Database Access, Web session handling/http and GUI development. The lack of reflection prevents ORMs (like Hibernate or LINQ), XML and JSON parsers that instancinate classes, Data serialization and many other thigns (where initially typeless data has to be used to create an instance of a class).

A compile time switch available to a software developer during the build process can be used to eliminate this 'you pay for what you use' concern.

I a firmwaredeveloper does not need the reflection to read data from a serial port -- then fine do not use the switch. But as a database developer who wants to keep using C++ I am constantly phased with a horrible, difficult to maintain code that maps Data between data members and database constructs.

Neither Boost serialization nor other mechanism are really solving the reflection -- it must be done by the compiler -- and once it is done C++ will be again tought in schools and used in software that are dealing with data processing

To me this issue #1 (and naitive threading primitives is issue #2).

  • 4
    Who said C++ *is* to be used as a language for DB Access, Web session hnadling or gui dev? There are plenty of far better languages to use for that kind of stuff. And a compile-time switch won't solve the problem. Usually, the decision to enable or disable reflection will not be on a per-file basis. It could work if it could be enabled on individual types. If the programmer can specify with an attribute or similar when defining a type, whether or not reflection metadata for it should be generated. But a global switch? You'd be crippling 90% of the lnaguage just to make 10% of it simpler. – jalf Sep 11 '09 at 15:36
  • Then, if I want a program that cross-platform and have access to a gui, what should I use? The inflexible java swing? The windows only C#? But truth should be told, and the truth is that there are a lot of programs that are compiled in executable code, and offer a gui interface and access to databases, so they must use some database and gui support... And they aren't using QT. (it should have been named MT (monster toolkit)) – Coyote21 May 30 '11 at 20:15
  • 1
    @Coyote21: C# hasn't been Windows-only for years. (Though i'm not a fan of Mono, it works well enough for most stuff.) And Swing isn't the only GUI toolkit for Java. Truth be told, either one would be a better choice if you want cross-platform. C++ is pretty much always going to have platform-specific parts here or there if you're doing anything non-trivial. – cHao Apr 17 '12 at 14:56
  • There is no reason why you need reflection for ORM. You can achieve all of that with templates. There area bunch of frameworks that provide ORM for C++. – MrFox Jul 06 '12 at 19:46
  • How does this actually answer the question? – Toby Speight Mar 26 '21 at 13:22
-1

C++ is a language that doesn't need reflection because C++ is a language that you would use to write a language that has reflection in it.

TJ Bandrowsky
  • 842
  • 8
  • 12
  • 4
    C++ can benefit from reflection just as much as any other language. It's that those benefits directly oppose it maximum performance and resource efficiency goals. – ATL_DEV Feb 27 '21 at 23:49