2011-11-25 55 views
10

我一直使用可變參數模板,充當C和C++之間接口中的異常防火牆。模板只需要一個函數,接着是N個參數,並在try catch塊內調用該函數。這一直工作正常,不幸的是我現在想調用的函數現在需要一個額外的默認參數。因此,函數名稱未被解析,模板無法編譯。可變模板,使用默認參數完美轉發到函數

的錯誤是:

perfect-forward.cpp: In function ‘void FuncCaller(Func, Args&& ...) [with Func = void (*)(const std::basic_string<char>&, double, const std::vector<int>&), Args = {const char (&)[7], double}]’ :
perfect-forward.cpp:69:41: instantiated from here
perfect-forward.cpp:46:4: error: too few arguments to function

代碼的簡化版本如下:

template< class Func, typename ...Args > 
void FuncCaller(Func f, Args&&... params) 
{ 
    try 
    { 
     cout << __func__ << " called\n"; 
     f(params...); 
    } 
    catch(std::exception& ex) 
    { 
     cout << "Caught exception: " << ex.what() << "\n"; 
    } 
} 

void Callee(const string& arg1, double d, const vector<int>&v = vector<int>{}) 
{ 
    cout << __func__ << " called\n"; 
    cout << "\targ1: " << arg1 << "\n"; 
    cout << "\td: " << d << "\n"; 
    cout << "\tv: "; 
    copy(v.begin(), v.end(), ostream_iterator<int>(cout, " " )); 
    cout << "\n"; 
} 

int main() 
{ 
    vector<int> v { 1, 2, 3, 4, 5 }; 

    FuncCaller(Callee, "string", 3.1415, v); 
    FuncCaller(Callee, "string", 3.1415); **// Fails to compile** 

    return 0; 
} 

如若此代碼的工作還是我的期望太高了從編譯器?

注:我已經測試使用完美轉發與具有默認參數和編譯代碼和按預期工作的構造,

即:

調用帶有2 cfollowing構造函數時
template<typename TypeToConstruct> struct SharedPtrAllocator 
{ 
    template<typename ...Args> shared_ptr<TypeToConstruct> 
     construct_with_shared_ptr(Args&&... params) { 
     return std::shared_ptr<TypeToConstruct>(new TypeToConstruct(std::forward<Args>(params)...)); 
    }; 
}; 

作品或3個參數...

MyClass1(const string& arg1, double d, const vector<int>&v = vector<int>{}) 
+2

(它應該是'f(std :: forward (params)...);',順便說一下。) –

回答

8

我不認爲有什麼辦法可以實現。默認參數值不是函數簽名的一部分。它們只是代碼生成的短手,在您按照字面意思調用函數時會被編譯器擴展。同樣,std::bind也不會選擇默認參數。

+1

我認爲這是很長的那些行......出於興趣,爲什麼轉發到構造函數與默認參數工作? – mark

+1

那麼,你可以直接調用這個函數,這就是你的代碼所做的(如果你解開所有的模板參數替換)。但在原始問題中,函數類型本身被推斷出來,這就是你失去默認參數的地方。 –