“候选模板被忽略:无法匹配……”模板函数的模板函数参数

问题描述 投票:2回答:3

概述

我正在尝试将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类型是什么?

c++ templates c++17 variadic-templates
3个回答
1
投票

在类情况下(Compose<A, B, C>),当您指定模板参数时/之后不会进行任何扣除。我们有T = A...S = B, C。一切正常。

但是在函数情况下(compose<A, B, C>(...)),编译器不知道这些是否都是模板参数,还是不应该推导其他参数。您可以从错误中收集信息:它提到function<A (B, C, type-parameter-0-1...)>,即在C之后不会停止。

当您尝试传递带有三个参数的std::function时,这种区别变得很明显:

std::function<A(B, C, D)> f;
compose<A, B, C>(f);

[此处,编译器推导compose<A, B, C, D>,即T = A...S = B, C, D。之所以进行编译,是因为编译器会尝试推导composeS包的其他参数。

Compose<A, B, C>(f);

无法编译:fcompose_fn_t<A, B, C>不匹配。编译器不执行Compose模板参数的推导。


1
投票

如果您为函数调用指定模板参数列表,如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的功能,但是您可以轻松实现自己的功能。它什么也不做,只返回在其value成员中给定的类型:

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

这不是类模板的问题,因为仅在根本不提供模板参数列表的情况下,才执行类模板参数推导。


0
投票

您的问题与c ++中的隐式转换有关。

© www.soinside.com 2019 - 2024. All rights reserved.