2017-12-27 371 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 ();) –