2017-12-27 282 views
0

我试图让编译器推导出正确的函数模板。 考虑下面的代码,正确的模板功能,推导出...传递重载函数指针作为参数重载模板函数

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 ::调用(& T,参数)调用正确的F功能。不过,如果我添加了重载F函数进行测试,然后(过载2个参数)将被调用(而不是正确的F与1个ARG)

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

我敢肯定,这是由于事实上编译器没有足够的信息来推断。我如何帮助编译器推断哪个重载的模板函数要调用?

类似下面的伪代码...(?表示未知类型的一些ARG)

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

有没有办法做到这一点?

回答

1

编译器无法知道变体类中存储了什么。因此?可以从函数类型(从它的参数)推导出只有。因此,您需要一些代码来检查args.size()是否与函数参数的编号相匹配。尽量做到以下几点:

  • 创建std::tuple<Args...>其中Args...从功能型评估
  • 检查args.size()是一样的,在std::tuple<Args...>
  • 元素转换您args向量的元组的数量。
  • 使用std::apply(或重新发明自己的)来调用带参数的函数从数组
+0

我想你的想法的变化,但它似乎并不十分吻合。如果函数类型在Call函数中未知,那么如何创建std :: tuple ?我会失去调用OVariant :: GetSafe的能力(T0 t0 = args [0] .GetSafe ();) –