簡體   English   中英

變體模板函數接受lambda

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM