簡體   English   中英

將函數傳遞給可變參數函數模板

[英]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::functionbar是一個指向函數的指針,該函數可以轉換為std::function但不是std::function

foo1()情況下,您顯式顯示RetTypeArgType模板參數,因此編譯器可以將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> ,你不是說“ RetTypevoidArgTypes...int 。你說的是ArgTypes... int 開頭

std::function<void(int, double)> x;
foo0<void, int>( x )

以上編譯好。

...

另一種方法是添加另一個重載。

留下這個:

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.

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