2

In the Cocoa Framework, all NSObjects implement a method - respondsToSelector: that returns a Boolean value indicating whether the receiver implements or inherits a method that can respond to a specified message. So if I wanted to check if my object foo has a method - bar:, I would use the message [foo respondsToSelector: @selector(bar:)];.

Is this behavior possible in C++ with an identical interface, either by implementing selectors as a struct or through using std::function objects as parameters? For example, the function definition would look like one of the following:

bool Foo::respondsToSelector(const std::function<?> &selector) {
    // Problem: Template arg and return types of this call would always be unknown.
}

bool Foo::respondsToSelector(const Selector *selector) {

}

Objective-C can determine selectors at either compile-time or run-time depending on whether @selector() or NSSelectorFromString() is used. I am asking for either.

Jared
  • 4,240
  • 4
  • 22
  • 27
  • I don't have time to flesh this out into a real answer at the moment, but the answer is most likely **no**, depending on your exact use case. Cocoa and Objective-C rely _very_ heavily on runtime [reflection](https://en.wikipedia.org/wiki/Reflection_(computer_programming)), a feature that is not really present in C++ (it's technically possible through RTTI or through external libraries, but in a rather limited sense). You may be able to implement some subset of this at compile-time with templates, but if you want runtime mechanisms you'll likely have to write them yourself. – Itai Ferber Jun 24 '16 at 17:10
  • Basically, it depends: what are you looking to do? – Itai Ferber Jun 24 '16 at 17:10
  • 1
    (To clarify — this is not to say that you can't write this in C++, you just have to add runtime-level introspection yourself; it isn't there out of the box. Nor will it be automatic: every class will need to manually figure out which selectors to respond with `true` or `false` for.) – Itai Ferber Jun 24 '16 at 17:16
  • To clarify on what I'm wanting with compile/run-time constraints, the call would be made during run-time as with any typical function call, but I don't care how the selectors are implemented or what the args for this function would be (function pointer, string, object, custom-made selector class, etc.). They can be made at either compile or run-time. So yes, I'm looking for run-time program introspection. – Jared Jun 24 '16 at 17:31
  • The way I'd imagine it is a common base class (brrrrr...) Object and then an ObjectImpl that somewhere, like in ctor, takes four template parameters: first is a list of std::pairs of 'string templates' (ctsting<'a', 'b', 'c'>) and the corresponding member function pointer; second is a similar one for pointers to static member functions; third is one for pointers to vars, fourth is for pointers to static vars. ObjectImpl then implements the virtuals you'd like from Object - and yes, you inherit virtually from ObjectImpl. I bet you can do it in 100 lines (and debug this design for 100 days). – lorro Jun 24 '16 at 17:31
  • @Iorro A common abstract base class would not be the end of the world for me, but yes, the rest your solution sounds very bug-prone. – Jared Jun 24 '16 at 17:38
  • @Jared Another question for you to help shape an answer to this. Are you looking for this feature to be "automatic", or would it be okay to be opt-in, in a sense? For example, you could have a base class called `Object`, which implements a virtual `respondsToSelector` method, inherited by child classes. Every class can override `respondsToSelector`, either manually inspecting the selector name and responding, looking it up in a manually created vtable, etc. You can then also have a virtual `performSelector` method to do manual dispatch in the same way. – Itai Ferber Jun 24 '16 at 20:26
  • A selector can be a simple struct containing just the name of the method (and any other information you personally find useful to pass around), and dispatching can be done manually with flow control (bunch of if-statements, passing things off to your parent class's `respondsToSelector` and `performSelector` if you don't implement it yourself), a custom inherited vtable implementation, etc. Whatever is easiest. This shouldn't be a ton of work unless you get fancy with it, but obviously, this isn't automatic in any sense. – Itai Ferber Jun 24 '16 at 20:28
  • @ItaiFerber I'm afraid your proposal wouldn't work as effectively as I would like it to be. I was hoping for this to be an automatic solution. A long string of user-written if-else statements would be tedious and O(n). Also, pairing function names to function pointers in a v-table or something like an std::map would not be possible since the functions would have different arg and return types. I may delve into the source code of Swift or GNUstep and see how their developers handled this, then report back in a bit. – Jared Jun 24 '16 at 21:28
  • @Jared Just to follow up -- if you're going to need it to be automatic, then yes, unfortunately, this solution won't work (though you can certainly get a working solution in less than O(n) like this). You'll need to look into either a C++ reflection library to help you out, or re-create the Objective-C runtime (or at least parts of it) in C++ and totally eschew type safety, or both. Without more information about your constraints, it's hard to give more in-depth advice than that, but I hope you find a solution that works for you! – Itai Ferber Jun 27 '16 at 17:28

2 Answers2

2

Objective C is a message passing OO system with reflection.

You can implement a message passing OO system with reflection in C++, but it does not consist of C++ classes with methods which recieve messages.

The end result could vary from "A C++ hosted scripting engine", to MFC style templates, to Q_OBJECT style moc, to manual q object code, to some custom dynamic library plugin solution, to a myriad of other options.

In language reflection at compile time is under active development.

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

It is possible with templates. Check out SFINAE and std::enable_if.

Community
  • 1
  • 1
0x5453
  • 12,753
  • 1
  • 32
  • 61