Danny Diaz
Danny Diaz

Reputation: 240

passing overloaded function pointer as argument to overloaded template function

I'm trying to get the compiler to deduce the correct function template. Given the following code, the correct templated function is deduced...

class TestBase{};

template <typename c, typename RT, typename T0>
inline void CallF( RT( c::*M )(T0), TestBase* pObject, std::vector<OVariant> args )
{
    //safely convert variant (implementations external to class)
    T0 t0 = args[0].GetSafe<T0>();

    ((static_cast<c*>(pObject))->*M)(t0);
}

template <typename c, typename RT, typename T0, typename T1>
inline void CallF( RT( c::*M )(T0, T1), TestBase* pObject, std::vector<OVariant> args )
{
    //safely convert variant (implementations external to class)
    T0 t0 = args[0].GetSafe<T0>();
    T1 t1 = args[1].GetSafe<T1>();

    ((static_cast<c*>(pObject))->*M)(t0, t1);
}

class Test : public TestBase
{
public:

    void F( s32 one )
    {
        std::cout << "one";
    }

    struct Wrapped_F
    {
        //OVariant is my typical variant class
        static void Call( TestBase* pObject, std::vector<OVariant> args )
        {
            ::CallF<Test>( &Test::F, pObject, args );
        }
    };
};

int main(int argc, char *argv[])
{
    Test t;
    OVariant i( 13 );
    std::vector<OVariant> args;
    args.push_back( i );

    t.Wrapped_F::Call( &t, args );
}

t.Wrapped_F::Call( &t, args ) calls the correct F function. However, if I add the overloaded F function to Test, then it (overload with 2 args) will be called (instead of the correct F with 1 arg)

void F( s32 one, s32 two )
{
    std::cout << "two";
}

I'm pretty sure this is due to the fact that the compiler does not have enough info to deduce. How can I help the compiler deduce which overloaded template function to call?

Something like the following pseudo code... (? to denote some arg of unknown type)

static void Call( TestBase* pObject, std::vector<OVariant> args )
{
    //Note: I won't know anything about the arguments to function F; I do know the size of the vector
    switch ( args.size() )
    {
    case 1:::CallF<Test,void,?>( &Test::F, pObject, args );
    case 2:::CallF<Test,void,?,?>( &Test::F, pObject, args );
    }
}

Is there a way to do this?

Upvotes: 0

Views: 226

Answers (1)

ivaigult
ivaigult

Reputation: 6667

The compiler has no way of knowing what is stored inside your variant class. So the ? could be deduced only from the function type (from its parameters). Hence, you will need some code to check that args.size() matches the number of function parameter. Try to do the following:

  • Create std::tuple<Args...> where Args... are evaluated from the function type
  • Check that args.size() is the same as number of elements in the std::tuple<Args...>
  • Convert your args vector to the tuple.
  • Use std::apply (or re-invent your own) to call your function with arguments from the tuple

Upvotes: 1

Related Questions