gpt4 book ai didi

c++ - "candidate template ignored: could not match ..."用于模板函数的模板函数参数

转载 作者:行者123 更新时间:2023-12-02 18:18:50 27 4
gpt4 key购买 nike

概述

我正在尝试将 lambda 传递给采用模板函数类型的模板函数。编译时出现错误 candidate template ignored: could not match... .

但是,当我尝试将相同的 lambda 传递给采用模板函数类型的模板类时,它会编译并运行。

问题

  1. 为什么这适用于模板类而不适用于模板函数?
  2. 有办法做到这一点吗?
  3. 当我使用模板函数尝试此操作时,模板函数类型的额外预期参数是什么(有关更多详细信息,请参阅下文)?

代码

考虑以下代码 (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;
}

当我使用 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.

这个额外的是什么type-parameter-0-1模板函数类型 ( compose_fn_t ) 所期望的类型?

最佳答案

如果为函数调用指定模板参数列表,如compose<A, B, C> ,那么如果模板参数多于实参,则该列表被视为部分列表。

调用该函数仍然会对剩余的模板参数进行模板实参推导。

在您的情况下,参数包的其余参数是根据 compose_fn_t 推导出来的。参数(前三个模板参数已经确定),但是失败了,因为 lambda 无法推导出 std::function类型。

您需要将函数参数中使用的模板参数强制放入非推导上下文中以避免这种情况。一种方法是使用

template<typename T, typename... S>
void compose(typename std::type_identity<compose_fn_t<T, S...>>::type fn) {};

由于范围解析运算符左侧的所有内容 ::是非推导的。但这也意味着,如果没有模板参数列表,您将无法调用该函数。

std::type_identity是 C++20 功能,但您可以轻松实现自己的功能。它什么也不做,只是返回 type 中赋予它的类型。成员(member):

template<typename T>
struct type_identity {
using type = T;
};

或者通过转发引用来获取参数并将其转发到 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
};
<小时/>

这不是类模板的问题,因为只有在根本没有提供模板参数列表的情况下才会执行类模板参数推导 (CTAD)。

<小时/>

您还可以在 std::function 上使用 CTAD选择正确的std::function为您提供特化,无需重复类型:

compose(std::function{[] (B b, C c) -> A { return {}; }});

您还可以将此结构移至 compose定义:

template<typename F>
void compose(F&& f) {
auto fn = std::function{std::forward<F>(f)};
// use fn here as before
};

以便调用

compose([] (B b, C c) -> A { return {}; });

足够了。

请注意,这两种情况都不适用于通用 lambda,并且还要注意,如果替换 std::function,它们也不起作用。与您的compose_fn_t别名,因为 CTAD 不是对别名进行的。

关于c++ - "candidate template ignored: could not match ..."用于模板函数的模板函数参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59356874/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com