"no matching function for call to" 当有一个带有模板参数的函数指针作为模板参数时

"no matching function for call to" when having a function pointer with template arguments as a template argument

我正在编写一个模板包装函数,它可以应用于具有不同 number/types 个参数的函数。 我有一些有效的代码,但我正在尝试将更多参数更改为模板参数。

工作代码:

#include <iostream>

int func0(bool b) { return b ? 1 : 2; }
//There is a few more funcX...

template<typename ...ARGS>
int wrapper(int (*func)(ARGS...), ARGS... args) { return (*func)(args...) * 10; }

int wrappedFunc0(bool b) { return wrapper<bool>(func0, b); }

int main()
{
    std::cout << wrappedFunc0(true) << std::endl;
    return 0;
}

现在我希望 int (*func)(ARGS...) 也成为模板参数。 (这是出于性能原因。我希望将指针返回到包装器中,因为我使用它的方式会阻止编译器对其进行优化。)

这是我想出的(唯一的区别是我将一个参数更改为模板参数。):

#include <iostream>

int func0(bool b) { return b ? 1 : 2; }
//There is a few more funcX...

template<typename ...ARGS, int (*FUNC)(ARGS...)>
int wrapper(ARGS... args) { return (*FUNC)(args...) * 10; }

int wrappedFunc0(bool b) { return wrapper<bool, func0>(b); }

int main()
{
    std::cout << wrappedFunc0(true) << std::endl;
    return 0;
}

这无法编译。它显示:

<source>: In function 'int wrappedFunc0(bool)':
<source>:9:55: error: no matching function for call to 'wrapper<bool, func0>(bool&)'
    9 | int wrappedFunc0(bool b) { return wrapper<bool, func0>(b); }
      |                                   ~~~~~~~~~~~~~~~~~~~~^~~
<source>:7:5: note: candidate: 'template<class ... ARGS, int (* FUNC)(ARGS ...)> int wrapper(ARGS ...)'
    7 | int wrapper(ARGS... args) { return (*FUNC)(args...) * 10; }
      |     ^~~~~~~
<source>:7:5: note:   template argument deduction/substitution failed:
<source>:9:55: error: type/value mismatch at argument 1 in template parameter list for 'template<class ... ARGS, int (* FUNC)(ARGS ...)> int wrapper(ARGS ...)'
    9 | int wrappedFunc0(bool b) { return wrapper<bool, func0>(b); }
      |                                   ~~~~~~~~~~~~~~~~~~~~^~~
<source>:9:55: note:   expected a type, got 'func0'
ASM generation compiler returned: 1
<source>: In function 'int wrappedFunc0(bool)':
<source>:9:55: error: no matching function for call to 'wrapper<bool, func0>(bool&)'
    9 | int wrappedFunc0(bool b) { return wrapper<bool, func0>(b); }
      |                                   ~~~~~~~~~~~~~~~~~~~~^~~
<source>:7:5: note: candidate: 'template<class ... ARGS, int (* FUNC)(ARGS ...)> int wrapper(ARGS ...)'
    7 | int wrapper(ARGS... args) { return (*FUNC)(args...) * 10; }
      |     ^~~~~~~
<source>:7:5: note:   template argument deduction/substitution failed:
<source>:9:55: error: type/value mismatch at argument 1 in template parameter list for 'template<class ... ARGS, int (* FUNC)(ARGS ...)> int wrapper(ARGS ...)'
    9 | int wrappedFunc0(bool b) { return wrapper<bool, func0>(b); }
      |                                   ~~~~~~~~~~~~~~~~~~~~^~~
<source>:9:55: note:   expected a type, got 'func0'
Execution build compiler returned: 1

(link to the compiler explorer)

在我看来这似乎是编译器的问题,但 GCC 和 Clang 都同意这一点,所以也许不是。

无论如何,如何使用指向函数的模板指针正确编译此模板?

编辑: 解决重复标志 我认为该问题的核心问题与我的问题相同,但是,它缺少允许将指针作为模板参数传递给函数(不仅是其类型)的解决方案。

这不起作用,因为一个包参数(包括 ... 的那个)消耗了所有剩余的参数。它后面的所有参数都不能明确指定,必须推导。

通常你会像这样写这样的包装器:

template <typename F, typename ...P>
int wrapper(F &&func, P &&... params)
{
    return std::forward<F>(func)(std::forward<P>(params)...) * 10;
}

(如果函数在包装器内被多次调用,除最后一次调用之外的所有调用都不能使用 std::forward。)

这将通过引用传递函数,这应该与使用函数指针完全相同,但我没有理由相信它会阻止编译器对其进行优化。

您可以通过传递 std::integral_constant<decltype(&func0), func0>{} 而不是 func0 来强制将函数编码到模板参数中,但同样,我认为它不会改变任何东西。

第二个代码段 无效 因为:

a type parameter pack cannot be expanded in its own parameter clause.

[temp.param]/17开始:

If a template-parameter is a type-parameter with an ellipsis prior to its optional identifier or is a parameter-declaration that declares a pack ([dcl.fct]), then the template-parameter is a template parameter pack. A template parameter pack that is a parameter-declaration whose type contains one or more unexpanded packs is a pack expansion. ... A template parameter pack that is a pack expansion shall not expand a template parameter pack declared in the same template-parameter-list.

因此请考虑以下无效示例:

template<typename... Ts, Ts... vals> struct mytuple {}; //invalid

上面的例子无效,因为模板类型参数包Ts不能在自己的参数列表中展开

出于同样的原因,您的代码示例无效。例如,msvc.

中第二个代码段的简化版本 doesn't compile