Return type of arbitrary function

Started by
4 comments, last by Juliean 8 years, 5 months ago

Hello,

I'm trying to improve the function binding for my script system. To do this, I need to retrive the return type of a certain class function at a certain point in the code. I'm working on MSVC2013 with C++11.

Without going into too much detail, here is some dummy code that shows what I am trying to accomplish:


template<typename Class>
class TypeInfo
{
public:

    using ReturnType = std::result_of<decltype(&Class::Call)(...)>::type; // what goes to ... ?
};

// test classes

class Testing
{
public:

    int Call(int) {}
};

class Testing2
{
public:

    float Call(std::string, double) {}
};

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    TypeInfo<Testing>::ReturnType a = 1; // a should be "int"
    TypeInfo<Testing2>::ReturnType b = 1.0f; b should be "float"
}

So what I want to do is pass an arbitrary class with a "Call" member function to the here-called TypeInfo-class, and this class should have the return-type of the call-function accessible as a typedef. I already found out that the std::result_of class can do this, BUT I cannot easily do it this way.

The problem is, that std::result_of needs to be called like this:


using ReturnType = std::result_of<decltype(&Testing::Call)(int)>::type;
using ReturnType = std::result_of<decltype(&Testing2::Call)(std::string, double)>::type;

where I explicitely need to specify the functions parameters after the decltype, which means that I cannot use this with functions with different function parameters, without specifiying them manually (what I do not want).

So the basic question is: Is there any way (ie. modifying my template class) so that result_of can be used with arbitrary function paramters?

If not, is there any other way using templates to extract the function return type in a manner that it is usable for me (I really do not care about things like multiple overloads of the same function etc...)?

I'm pretty sure there ought to be a sane solution for this, I'm just stuck here. I know I can make a templated function that achieves pretty much what I want:


template<typename Return, typename... Args>
void createReturnFunctionBinding(Return(*FunctionPointer)(Args...))
{
    // now Return has the value of whichever function I pass in like...
}

int testing(float, double, int);
createReturnFunctionBinding(&testing); // Return is int

But I don't know how to make a class template that does the same, which I need here because I need the return type as a typedef. Any ideas?

Thanks in advance

Advertisement
This might get you going in the right direction:


template <typename ReturnT, typename... ParamTs>
class TDelegateWrapper {
public:
    typedef ReturnT (*FunctorT)(ParamTs...);

public:
    TDelegateWrapper (const FunctorT & functor)
        : m_functor(functor)
    { }

public:
    ReturnT Invoke (ParamTs ... args) {
        return m_functor(std::forward<ParamTs>(args)...);
    };

private:
    FunctorT m_functor;
};


template <typename... ParamTs, typename LambdaT>
auto MakeDelegate (LambdaT && lambda) -> TDelegateWrapper<decltype(lambda(std::declval<ParamTs>()...)), ParamTs...> {
    return TDelegateWrapper<decltype(lambda(std::declval<ParamTs>()...)), ParamTs...>(lambda);
}
Disclaimer: I'm just starting to futz with C++14 so I don't know if I'm doing anything terribly wrong here.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]


#include <iostream>
#include <type_traits>

template<class C, class T, class... Args>
T result_of(T (C::*)(Args...)) {
    return T();
}

template<typename T>
class S {
public:
    using ResultType = decltype(result_of(&T::C));
};

class A {
public:
    int C(int) {
        return 0;
    }
};

class B {
public:
    float C(float, float) {
        return 0;
    }
};

int main() {
    S<A>::ResultType x;
    std::cout<<typeid(x).name()<<std::endl;

    S<B>::ResultType y;
    std::cout << typeid(y).name() << std::endl;
}

In time the project grows, the ignorance of its devs it shows, with many a convoluted function, it plunges into deep compunction, the price of failure is high, Washu's mirth is nigh.

Thank you both, very helpful, thats what I was looking for.

Now there has been another template related issue though, that lies more within the structure of this whole thing, so I'd like to ask this here as well.

Now that I can access the return type, there is still one problem with how I exactly use this thing.

What I have is a class the derives from a specific parent class, which takes the derived class as a template argument to access the "Call" function. This worked as long as I only used this call function from within the parents class function bodies, but now when I make a general typedef using the return type of this "Call"-funciton, I get C2039 "Call is not an element of Derived":


template<typename Derived>
class Parent
{
    using ReturnType = RETURN_TYPE_CLASS(Derived::Call); // macro for wrapping the decltype-syntax, I checked that there is no error there

    Parent(void)
    {
         (Derived*)(this)->(&Derived::Call)();// as ugly as this is (and probably wrong syntax), acessing Derived::Call still works here
    }

private:

    ReturnType something; // I do need the return type as part of the class
};

class Child :
    public Parent<Child>
{
public:

    int Call(void);
};

I think I do understand the reasoning, at this point the class is not fully constructed and the compiler doesn't see the "Call" yet, probably the same reason why you cannot do certain static_asserts in the body of a class (is_base_of, ...). I have the same effect when I try to pass the function as a template parameter, too:


class Child:
    public Parent<Child, decltype(&Child::Call)> // same error on this line now

So uhm, I'm a little pesimistic that there is a direct solution to this, but I'm asking anyways: Anything I can do here? I'd also take any workarounds and changes to the structure of what I'm doing here. Please let me know if you need more information about the actual classes I'm using here.

Thanks again.

Note that casting "this" to a derived class in a constructor is naughty. Your Derived object is not constructed yet so who knows what might happen.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]


Note that casting "this" to a derived class in a constructor is naughty. Your Derived object is not constructed yet so who knows what might happen.

True, its not what I'm actually doing in the implementation, was just a (probably bad) example of that I am actually able to access Call in any function beginning with the constructor.

This topic is closed to new replies.

Advertisement