передача указателя перегруженной функции в качестве аргумента перегруженной функции шаблона

Я пытаюсь заставить компилятор вывести правильный шаблон функции. Учитывая следующий код, выводится правильная шаблонная функция...

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 ) вызывает правильную F-функцию. Однако, если я добавлю в Test перегруженную функцию F, то она (перегрузка с 2 аргументами) будет вызвана (вместо правильной F с 1 аргументом)

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

Я почти уверен, что это связано с тем, что у компилятора недостаточно информации для вывода. Как я могу помочь компилятору определить, какую перегруженную функцию шаблона вызывать?

Что-то вроде следующего псевдокода... (? для обозначения некоторого аргумента неизвестного типа)

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 );
    }
}

Есть ли способ сделать это?


person Danny Diaz    schedule 27.12.2017    source источник


Ответы (1)


У компилятора нет возможности узнать, что хранится внутри вашего вариантного класса. Таким образом, ? можно вывести только из типа функции (из ее параметров). Следовательно, вам понадобится код, чтобы проверить, что args.size() соответствует номеру параметра функции. Попробуйте сделать следующее:

  • Создайте std::tuple<Args...>, где Args... вычисляются из типа функции
  • Убедитесь, что args.size() совпадает с количеством элементов в std::tuple<Args...>
  • Преобразуйте свой вектор args в кортеж.
  • Используйте std::apply (или заново изобретите свой собственный) для вызова вашей функции с аргументами из кортежа
person ivaigult    schedule 27.12.2017
comment
Я пробовал варианты вашей идеи, но она не совсем подходит. Как будет работать создание std::tuple‹Args...›, если тип функции неизвестен в функции Call? Потеряю ли я возможность вызывать OVariant::GetSafe (T0 t0 = args[0].GetSafe‹T0›();) - person Danny Diaz; 27.12.2017