1

first post, so hopefully not violating any etiquette. Feel free to give suggestions for making the question better.

I've seen a few posts similar to this one: Check if a class has a member function of a given signature, but none do quite what I want. Sure it "works with polymorphism" in the sense that it can properly check subclass types for the function that comes from a superclass, but what I'd like to do is check the object itself and not the class. Using some (slightly tweaked) code from that post:

// Somewhere in back-end
#include <type_traits>
template<typename, typename T>
struct HasFunction {
    static_assert(integral_constant<T, false>::value,
        "Second template parameter needs to be of function type."
        );
};

template<typename C, typename Ret, typename... Args>
class HasFunction<C, Ret(Args...)> {

    template<typename T>
    static constexpr auto check(T*) -> typename is_same< 
        decltype(declval<T>().myfunc(declval<Args>()...)), Ret>::type;

    template<typename>
    static constexpr false_type check(...);

    typedef decltype(check<C>(0)) type;
public:
    static constexpr bool value = type::value;
};

struct W {};
struct X : W { int myfunc(double) { return 42; } };
struct Y : X {};

I'd like to have something like the following:

// somewhere else in back-end. Called by client code and doesn't know
// what it's been passed!
template <class T>
void DoSomething(T& obj) {
    if (HasFunction<T, int(double)>::value)
        cout << "Found it!" << endl;
        // Do something with obj.myfunc
    else cout << "Nothin to see here" << endl;
}

int main()
{
    Y y;
    W* w = &y; // same object
    DoSomething(y); // Found it!
    DoSomething(*w); // Nothin to see here?
}

The problem is that the same object being viewed polymorphically causes different results (because the deduced type is what is being checked and not the object). So for example, if I was iterating over a collection of W*'s and calling DoSomething I would want it to no-op on W's but it should do something for X's and Y's. Is this achievable? I'm still digging into templates so I'm still not quite sure what's possible but it seems like it isn't. Is there a different way of doing it altogether?

Also, slightly less related to that specific problem: Is there a way to make HasFunction more like an interface so I could arbitrarily check for different functions? i.e. not have ".myfunc" concrete within it? (seems like it's only possible with macros?) e.g.

template<typename T>
struct HasFoo<T> : HasFunction<T, int foo(void)> {};
int main() {
    Bar b;
    if(HasFoo<b>::value) b.foo();
}

Obviously that's invalid syntax but hopefully it gets the point across.

GGS
  • 57
  • 7
  • Quite unclear what you mean by: "but what I'd like to do is check the object itself and not the class. " A object has the attributes of its class, so what is the difference? – Klaus Jun 02 '19 at 07:39
  • @Klaus - If I understand correctly what the OP mean, he has an object of a derived type and pass it as pointer of a base type. He want to know if it's possible to detects, from the pointer to the base type, if the original objects has a method with a specific name and signature. – max66 Jun 02 '19 at 09:44
  • Yes, @max66 is correct. I don't quite know how the underlying organization works but my original thought was that the object must carry some kind of function lookup table with it to resolve virtual and inherited function calls, and you should be able to reach into that function table to see if a particular one exists. But, actually it seems that c++ objects don't carry that information, so what functions are available are purely based on the type that you view it as – GGS Jun 02 '19 at 19:09

1 Answers1

0

It's just not possible to perform deep inspection on a base class pointer in order to check for possible member functions on the pointed-to type (for derived types that are not known ahead of time). Even if we get reflection.

The C++ standard provides us no way to perform this kind of inspection, because the kind of run time type information that is guaranteed to be available is very limited, basically relegated to the type_info structure.

Your compiler/platform may provide additional run-time type information that you can hook into, although the exact types and machinery used to provide RTTI are generally undocumented and difficult to examine (This article by Quarkslab attempts to inspect MSVC's RTTI hierarchy)

AndyG
  • 39,700
  • 8
  • 109
  • 143