再現您的問題一個簡單的例子:
void f(int) {}
void f(double) {}
template<class T> void call_with_3(T t) { t(3); }
int main() {
call_with_3(f);
}
在這裏我們可以看到,f
調用不能在這裏我們把它傳遞給call_with_3
點確定。現在,您看起來沒有多重過載(您只有一個f
!),但是...
A template
不是一個實例。 A template
函數是函數的工廠,而不是函數。
沒有任何東西可以傳遞。
當您將函數名稱作爲參數傳遞時,重載決議開始執行。如果目標類型是已知的(作爲函數引用或指針),它將用於對函數名稱進行重載解析。
在這種情況下,您將函數名稱傳遞給template
(auto
參數),因此沒有可以完成的重載解析,因此沒有找到特定的值,因此會出現錯誤。
您可以創建一個對象,其效果是對給定函數名稱的調用參數執行重載解析。我稱它們爲重載集對象。
static struct f_overload_set_t {
template<class... Args>
auto operator()(Args&&... args) const {
return f(std::forward<Args>(args)...);
}
} f_overload_set;
在C++ 11你所需要的const
後->decltype(f(std::declval<Args>()...))
。
現在f_overload_set(blah)
將被調用時將(幾乎)做什麼,當你f(blah)
,但f_overload_set
是一個實際的對象。所以你可以傳遞它。
生成此類過載集的宏相對容易編寫。他們也可以使用lambdas,因爲如果你仔細想想,上面的內容很像無狀態的lambda。
無狀態的基於lambda的宏過載集生成器的好處是它可以在使用點創建。從上面@ DYP的評論:
#define OVERLOAD_SET(FUNC)\
([](auto&&... args){\
return FUNC(std::forward<decltype(args)>(args)...);\
})
(注:約FUNC
沒有括號,如阻止ADL)。周圍的一切括號,因爲否則的話標操作(operator[]
)中,它會被解析爲[[
開始的屬性,其他點之間(感謝@ecatmur))
使你的代碼:
template<typename... ARGS>
void f(const std::tuple<ARGS...>& t){}
int main() {
tuple(1,2,3)(std_tuple)(OVERLOAD_SET(f));
}
的應用閉合類型的操作是一樣'模板 decltype(自動)操作者的功能模板()(T)',它不能推斷出類型只是ID-表達'F'。你可以將'f'換成lambda,'[](auto const&t){return f(t); }' –
dyp
2014-08-27 18:02:48
對於C++ 14的多態lambda表達式,完美轉發lambda包裝來傳遞重載集合是非常有用的。不幸的是,這是一些沒有宏的樣板文件:'#define LAMBDA_WRAP(FUN)([](auto && ... args){return FUN(std :: forward(args)...);}) ' –
dyp
2014-08-27 18:10:25
@dyp爲什麼'()'在lambda周圍? – Yakk 2014-08-27 19:43:27