[英]Variadic template function accepting lambda
我試圖理解我在下面的代碼中得到的編譯器錯誤。 我有一個可變參數模板函數,它接受一個具有指定類型的lambda,並且嘗試調用該函數會導致模板由於不匹配而不被視為有效候選。
#include <functional>
template<typename ... ResultTypes>
void executeWithResultHandler(std::function<void (ResultTypes...)> lambda)
{
}
int main(int argc, char **argv)
{
executeWithResultHandler<int>([] (int arg) {
});
return 0;
}
這會導致以下錯誤:
$ c++ -std=c++11 reduction.cpp
reduction.cpp:10:5: error: no matching function for call to 'executeWithResultHandler'
executeWithResultHandler<int>([] (int arg) {
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
reduction.cpp:4:6: note: candidate template ignored: could not match 'function<void (int, type-parameter-0-0...)>' against
'<lambda at reduction.cpp:10:35>'
void executeWithResultHandler(std::function<void (ResultTypes...)> lambda)
^
1 error generated.
如果我將聲明更改為variadic:
template<typename ResultType>
void executeWithResultHandler(std::function<void (ResultType)> lambda)
{
}
然后它適用於上面的玩具示例,但對於真正的問題,我需要任意參數。 有沒有我在這里缺少的東西,或者其他方法來實現這一目標?
編輯:這被標記為重復不正確,我相信 - 這個騙局沒有回答我問的問題。 這個問題特別與這里的可變參數模板問題有關:請注意,當我將模板切換為非可變參數時,lambda正確地轉換為std :: function類型,如預期的那樣。 無論參數的數量是多少都是如此,只要不以可變方式處理。
但是,它沒有特別適用於可變參數版本,盡管期望參數包被解包為一組實際參數,並且在函數調用站點顯式指定模板參數列表。
在你的情況下,可變參數模板的問題是編譯器不知道你明確指定的int
是否是ResultTypes...
的完整列表ResultTypes...
所以它試圖從你給它的參數中推導出可選的剩余參數,並且這顯然是失敗的。 這是可變參數模板參數的常見缺陷,並不僅限於lambdas。
解決方案始終意味着您從編譯器中刪除此選項,例如
template<typename ... ResultTypes>
void executeWithResultHandler_impl(std::function<void (ResultTypes...)> lambda)
{
}
template<typename ... ResultTypes, typename F>
void executeWithResultHandler(F&& lambda)
{
executeWithResultHandler_impl(std::function<void (ResultTypes...)>(lambda));
}
我之前將其作為重復鏈接的問題可以准確地解釋您的情況。
std::function
不是 lambda,它是可以存儲任何類型的可調用對象的容器類型。 您可以將lambda分配給std::function
,但在這種情況下,必需的轉換由std::function
構造std::function
執行。
在你的例子中
template<typename ... ResultTypes>
void executeWithResultHandler(std::function<void (ResultTypes...)> lambda)
{}
executeWithResultHandler<int>([](int arg){});
編譯器無法從上面的lambda表達式推斷參數包ResultTypes
的類型。 模板參數推導需要完全匹配,不考慮隱式轉換,並且如前所述,此處涉及的類型完全不同。
如果我將聲明更改為variadic,那么它可以工作
template<typename ResultType>
void executeWithResultHandler(std::function<void (ResultType)> lambda)
{}
executeWithResultHandler<int>([](int arg){});
這是有效的,因為不再涉及模板參數推斷。 executeWithResultHandler
接受一個你明確指定的模板參數,並且因為lambda可以隱式轉換為std::function
,所以重載解析會找到匹配項。
請注意,在第一種情況下,除了int
之外,可能還有更多的模板參數,您沒有明確指定。
您可以通過將lambda顯式轉換為std::function
來獲得原始示例。
executeWithResultHandler<int>(std::function<void(int)>([] (int arg) {}));
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.