[英]"candidate template ignored: could not match ..." for template function argument to template function
i am attempting to pass a lambda to a template function which takes a template function type.我试图将 lambda 传递给采用模板函数类型的模板函数。 on compilation is errors with
candidate template ignored: could not match...
.编译时出现错误,
candidate template ignored: could not match...
however, when i try to pass the same lambda to a template class which takes a template function type, it compiles and works.但是,当我尝试将相同的 lambda 传递给采用模板函数类型的模板类时,它会编译并工作。
consider the following code (c++17)考虑以下代码 (c++17)
#include <functional>
// define the template function type
template<typename T, typename...S>
using compose_fn_t = std::function<T(S...)>;
// define a template function which accepts the template function type
template<typename T, typename... S>
void compose(compose_fn_t<T, S...> fn) {};
// define a template class which accepts the template function type
template<typename T, typename... S>
class Compose {
public:
Compose(compose_fn_t<T, S...> fn) {};
};
// some arbitrary types
struct A{};
struct B{};
struct C{};
int main() {
compose<A, B, C>
([] (B b, C c) -> A { return {}; }); // this will not compile!
Compose<A, B, C>
([] (B b, C c) -> A { return {}; }); // this compiles and runs correctly!
return 0;
}
when i compile using compose<A, B, C>
, it throws the following error当我使用
compose<A, B, C>
编译时,它会抛出以下错误
$ g++ -std=c++17 -o main main.cpp
main.cpp:18:3: error: no matching function for call to 'compose'
compose<A, B, C>
^~~~~~~~~~~~~~~~
main.cpp:8:6: note: candidate template ignored: could not match 'function<A (B, C, type-parameter-0-1...)>' against '(lambda at main.cpp:19:6)'
void compose(compose_fn_t<T, S...> fn) {
^
1 error generated.
what is this additional type-parameter-0-1
type that is expected by the template function type ( compose_fn_t
)?模板函数类型 (
compose_fn_t
) 所期望的这个额外的type-parameter-0-1
类型是什么?
If you specify a template argument list for a function call, as in compose<A, B, C>
, then this list is considered partial if there are more template parameters than arguments.如果您为函数调用指定模板参数列表,如
compose<A, B, C>
,那么如果模板参数多于参数,则该列表被视为部分列表。
Calling the function still does template argument deduction on the remaining template parameters.调用该函数仍然对剩余的模板参数进行模板参数推导。
In your case the remaining parameters of the parameter pack are deduced against the compose_fn_t
parameter (with the first three template arguments already determined), but that fails, because the lambda cannot be deduced to a std::function
type.在您的情况下,参数包的其余参数是根据
compose_fn_t
参数(已经确定前三个模板参数)推导出来的,但是失败了,因为无法将 lambda 推导出为std::function
类型。
You need to force the template parameters used in the function parameter into a non-deduced context in order to avoid this.您需要将函数参数中使用的模板参数强制转换为非推导上下文以避免这种情况。 One way is to use
一种方法是使用
template<typename T, typename... S>
void compose(typename std::type_identity<compose_fn_t<T, S...>>::type fn) {};
since everything to the left-hand side of the scope resolution operator ::
is non-deduced.因为作用域解析运算符
::
左侧的所有内容都是非推导的。 This does however also mean, that you will not be able to call the function without a template argument list.然而,这也意味着,如果没有模板参数列表,您将无法调用该函数。
std::type_identity
is a C++20 feature, but you can easily implement your own. std::type_identity
是 C++20 特性,但您可以轻松实现自己的特性。 It does nothing but return the type given to it in its type
member:它只返回在其
type
成员中赋予它的type
:
template<typename T>
struct type_identity {
using type = T;
};
Alternatively take the argument by forwarding reference and forward it into a std::function
construction in the body of the function, avoiding any deduction:或者通过转发引用来获取参数,并将其转发到
std::function
体中的std::function
结构中,避免任何推论:
template<typename T, typename... S, typename F>
void compose(F&& f) {
compose_fn_t<T, S...> fn{std::forward<F>(f)};
// Use fn as before
};
This is not a problem with the class template, because class template argument deduction (CTAD) is only performed if no template argument list is provided at all.这不是类模板的问题,因为类模板参数推导 (CTAD) 仅在根本没有提供模板参数列表时才执行。
You can also use CTAD on std::function
to choose the correct std::function
specialization for you, without having to repeat the types:您还可以在
std::function
上使用 CTAD 为您选择正确的std::function
专业化,而无需重复类型:
compose(std::function{[] (B b, C c) -> A { return {}; }});
You can also move this construction into the compose
definition:您还可以将此构造移动到
compose
定义中:
template<typename F>
void compose(F&& f) {
auto fn = std::function{std::forward<F>(f)};
// use fn here as before
};
so that the call以便调用
compose([] (B b, C c) -> A { return {}; });
is sufficient.足够了。
Note that both of these cases don't work with generic lambdas and also note that they don't work if you replace std::function
with your compose_fn_t
alias, because CTAD is not done on aliases.请注意,这两种情况都不适用于通用 lambda,还要注意,如果您将
std::function
替换为compose_fn_t
别名,它们将compose_fn_t
,因为compose_fn_t
别名上完成。
In the class case ( Compose<A, B, C>
) no deduction takes place when/after you specify the template arguments.在类情况 (
Compose<A, B, C>
) 中,在指定模板参数时/之后不会发生任何推论。 We have T = A
and ...S = B, C
.我们有
T = A
和...S = B, C
。 Everything works as expected.一切都按预期工作。
But in the function case ( compose<A, B, C>(...)
), the compiler doesn't know whether these are all the template arguments or whether it is supposed to deduce additional ones.但是在函数情况下(
compose<A, B, C>(...)
),编译器不知道这些是所有模板参数还是应该推导出额外的参数。 You can glean this from the error: It mentions function<A (B, C, type-parameter-0-1...)>
, ie it doesn't stop after C
.您可以从错误中收集到这一点:它提到了
function<A (B, C, type-parameter-0-1...)>
,即它不会在C
之后停止。
This difference becomes clear when you attempt to pass a std::function
taking three arguments:当您尝试传递带有三个参数的
std::function
时,这种差异变得很明显:
std::function<A(B, C, D)> f;
compose<A, B, C>(f);
Here, the compiler deduces compose<A, B, C, D>
, ie T = A
and ...S = B, C, D
.在这里,编译器推导出
compose<A, B, C, D>
,即T = A
和...S = B, C, D
。 This compiles because the compiler tries to deduce additional arguments for compose
's S
pack.这是因为编译器试图为
compose
的S
包推导出额外的参数。
Compose<A, B, C>(f);
This does not compile: f
does not match compose_fn_t<A, B, C>
.这不会编译:
f
不匹配compose_fn_t<A, B, C>
。 The compiler doesn't perform deduction of the Compose
template arguments.编译器不执行
Compose
模板参数的推导。
Your problem is about the implicit conversion in c++.您的问题是关于 C++ 中的隐式转换。
Replace:代替:
compose<A, B, C>([] (B b, C c) -> A { return {}; }); // this will not compile!
With:和:
compose<A, B, C>((compose_fn_t<A, B, C>)([] (B b, C c) -> A { return {}; })); // this will compile!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.