[英]Passing a function to a variadic function template
Consider the following function templates: 考虑以下功能模板:
template<typename RetType, typename... ArgTypes>
void foo0(std::function<RetType(ArgTypes...)> f) {}
template<typename RetType, typename ArgType>
void foo1(std::function<RetType(ArgType)> f) {}
And the following function: 并具有以下功能:
void bar(int n) {}
Why does the following occur: 为什么会发生以下情况:
foo0<void, int>(bar); // does not compile
foo1<void, int>(bar); // compiles fine
The compilation error is (gcc-8 with C++17): 编译错误是(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);
Using a dummy template 使用虚拟模板
template<typename T>
void bar(int n) {}
makes foo0<void, int>(bar<int>);
使
foo0<void, int>(bar<int>);
compile fine in gcc-8 but gives an error using clang with Apple LLVM version 10.0.0 (clang-1000.11.45.5). 在gcc-8中编译正常,但在使用Apple LLVM 10.0.0版(clang-1000.11.45.5)的clang时出错。
The clang error is 铿锵的错误是
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) {}
Why does the following occur [?]
为什么会出现以下情况[?]
Take in count that when you call 当你打电话时,请记住
foo0<void, int>(bar); // compilation error
foo1<void, int>(bar); // compile
foo0()
and foo1()
are expecting a std::function
and bar
is a pointer to a function that can be converted to a std::function
but isn't a std::function
. foo0()
和foo1()
期望一个std::function
, bar
是一个指向函数的指针,该函数可以转换为std::function
但不是std::function
。
In the foo1()
case, you explicit both RetType
and ArgType
template parameters, so the compiler can convert bar
to a std::function<void(int)>
and all goes well. 在
foo1()
情况下,您显式显示RetType
和ArgType
模板参数,因此编译器可以将bar
转换为std::function<void(int)>
,一切顺利。
But the foo0()
case is different because the template parameter ArgTypes...
is a variadic one and calling foo0<void, int>(bar)
you don't explicit the full ArgTypes...
variadic list but only the first type. 但是
foo0()
情况是不同的,因为模板参数ArgTypes...
是一个可变参数并调用foo0<void, int>(bar)
你没有显式完整的ArgTypes...
variadic列表但只有第一种类型。
If I'm not wrong, the problem is that the compiler try to deduce the rest of ArgTypes...
from the bar
argument but bar
isn't a std::function
so the compiler is unable to deduce the rest of ArgTypes...
, so the error. 如果我没错,问题是编译器试图从
bar
参数中推导出其余的ArgTypes...
但是bar
不是std::function
因此编译器无法推断出其余的ArgTypes...
,这样的错误。
I suppose that 我想
foo0<void, int>(std::function<void(int)>{bar});
or simply 或者干脆
foo0(std::function<void(int)>{bar});
or (C++17 only) also 或者(仅限C ++ 17)
foo0(std::function{bar});
should compile because, calling foo0()
this way, the function receive a std::function
so the compiler can completely deduce the template parameters. 应该编译因为,这样调用
foo0()
,函数接收一个std::function
这样编译器就可以完全推导出模板参数。
I don't understand how the version with bar()
with a dummy template parameter 我不明白带有虚拟模板参数的
bar()
的版本如何
foo0<void, int>(bar<int>);
can compile with g++-8 and I suppose it's a g++ bug. 可以用g ++ - 8编译,我想这是一个g ++ bug。
template<typename RetType, typename... ArgTypes>
void foo0(std::function<RetType(ArgTypes...)> f) {}
the fix is: 修复是:
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) {}
and now your foo0<void, int>(bar)
compiles. 现在你的
foo0<void, int>(bar)
编译。
The general problem is that saying foo0<void, int>
, you aren't saying " RetType
is void
and ArgTypes...
is int
. You are saying ArgTypes...
starts with int
. 一般的问题是说
foo0<void, int>
,你不是说“ RetType
是void
, ArgTypes...
是int
。你说的是ArgTypes...
以 int
开头 。
std::function<void(int, double)> x;
foo0<void, int>( x )
the above compiles fine. 以上编译好。
... ...
Another approach in c++17 is to add another overload. c ++ 17中的另一种方法是添加另一个重载。
Leave this one: 留下这个:
template<typename RetType, typename... ArgTypes>
void foo2(block_deduction_t<std::function<RetType(ArgTypes...)>> f) {}
but add: 但添加:
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)} );
}
here we wrap F
into a construction-guided std::function
. 这里我们将
F
包装成一个构造引导的std::function
。
Your call to foo2<int, void>( bar )
now calls foo2<void, int, decltype(bar)&>
, the 2nd overload. 你对
foo2<int, void>( bar )
调用现在调用foo2<void, int, decltype(bar)&>
,第二个重载。 Then it proceeds to construct a std::function
from it, and so long as the signatures match exactly it works. 然后它继续从它构造一个
std::function
,只要签名完全匹配就可以了。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.