[英]Passing a function to a variadic function template
考慮以下功能模板:
template<typename RetType, typename... ArgTypes>
void foo0(std::function<RetType(ArgTypes...)> f) {}
template<typename RetType, typename ArgType>
void foo1(std::function<RetType(ArgType)> f) {}
並具有以下功能:
void bar(int n) {}
為什么會發生以下情況:
foo0<void, int>(bar); // does not compile
foo1<void, int>(bar); // compiles fine
編譯錯誤是(gcc-8 with C ++ 17):
error: no matching function for call to 'foo0<void, int>(void (&)(int))'
foo0<void, int>(bar);
^
note: candidate: 'template<class RetType, class ... ArgTypes> void foo0(std::function<_Res(_ArgTypes ...)>)'
void foo0(std::function<RetType(ArgTypes...)> f) {}
^~~~
note: template argument deduction/substitution failed:
note: mismatched types 'std::function<void(_ArgTypes ...)>' and 'void (*)(int)'
foo0<void, int>(bar);
使用虛擬模板
template<typename T>
void bar(int n) {}
使foo0<void, int>(bar<int>);
在gcc-8中編譯正常,但在使用Apple LLVM 10.0.0版(clang-1000.11.45.5)的clang時出錯。
鏗鏘的錯誤是
error: no matching function for call to 'foo0'
foo0<void, int>(bar<int>);
^~~~~~~~~~~~~~~
note: candidate template ignored: could not match 'function<void (int, type-parameter-0-1...)>' against 'void (*)(int)'
void foo0(std::function<RetType(ArgTypes...)> f) {}
為什么會出現以下情況[?]
當你打電話時,請記住
foo0<void, int>(bar); // compilation error
foo1<void, int>(bar); // compile
foo0()
和foo1()
期望一個std::function
, bar
是一個指向函數的指針,該函數可以轉換為std::function
但不是std::function
。
在foo1()
情況下,您顯式顯示RetType
和ArgType
模板參數,因此編譯器可以將bar
轉換為std::function<void(int)>
,一切順利。
但是foo0()
情況是不同的,因為模板參數ArgTypes...
是一個可變參數並調用foo0<void, int>(bar)
你沒有顯式完整的ArgTypes...
variadic列表但只有第一種類型。
如果我沒錯,問題是編譯器試圖從bar
參數中推導出其余的ArgTypes...
但是bar
不是std::function
因此編譯器無法推斷出其余的ArgTypes...
,這樣的錯誤。
我想
foo0<void, int>(std::function<void(int)>{bar});
或者干脆
foo0(std::function<void(int)>{bar});
或者(僅限C ++ 17)
foo0(std::function{bar});
應該編譯因為,這樣調用foo0()
,函數接收一個std::function
這樣編譯器就可以完全推導出模板參數。
我不明白帶有虛擬模板參數的bar()
的版本如何
foo0<void, int>(bar<int>);
可以用g ++ - 8編譯,我想這是一個g ++ bug。
template<typename RetType, typename... ArgTypes>
void foo0(std::function<RetType(ArgTypes...)> f) {}
修復是:
template<class X>struct tag_t{using type=X;};
template<class X>using block_deduction = typename tag_t<X>::type;
template<typename RetType, typename... ArgTypes>
void foo0(block_deduction_t<std::function<RetType(ArgTypes...)>> f) {}
現在你的foo0<void, int>(bar)
編譯。
一般的問題是說foo0<void, int>
,你不是說“ RetType
是void
, ArgTypes...
是int
。你說的是ArgTypes...
以 int
開頭 。
std::function<void(int, double)> x;
foo0<void, int>( x )
以上編譯好。
...
c ++ 17中的另一種方法是添加另一個重載。
留下這個:
template<typename RetType, typename... ArgTypes>
void foo2(block_deduction_t<std::function<RetType(ArgTypes...)>> f) {}
但添加:
template<typename RetType, typename... ArgTypes, class F>
void foo2(F&& f) {
return foo2<RetType, ArgTypes...>( std::function{std::forward<F>(f)} );
}
template<int unused, class F>
void foo2(F&& f) {
return foo2( std::function{std::forward<F>(f)} );
}
這里我們將F
包裝成一個構造引導的std::function
。
你對foo2<int, void>( bar )
調用現在調用foo2<void, int, decltype(bar)&>
,第二個重載。 然后它繼續從它構造一個std::function
,只要簽名完全匹配就可以了。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.