从函数指针数组中传递函数指针作为模板参数


9

我想将功能指针数组中的功能指针作为模板参数传递。即使Intellisense抱怨有些问题,我的代码似乎还是使用MSVC编译的。gcc和clang均无法编译代码。

考虑以下示例:

static void test() {}

using FunctionPointer = void(*)();

static constexpr FunctionPointer functions[] = { test };

template <FunctionPointer function>
static void wrapper_function()
{
    function();
}

int main()
{
    test();  // OK
    functions[0]();  // OK

    wrapper_function<test>();  // OK
    wrapper_function<functions[0]>();  // Error?
}

MSVC编译代码,但是Intellisense给出以下错误:invalid nontype template argument of type "const FunctionPointer"

gcc无法通过以下消息进行编译:

<source>: In function 'int main()':
<source>:19:33: error: no matching function for call to 'wrapper_function<functions[0]>()'
   19 |  wrapper_function<functions[0]>();  // Error?
      |                                 ^
<source>:8:13: note: candidate: 'template<void (* function)()> void wrapper_function()'
    8 | static void wrapper_function()
      |             ^~~~~~~~~~~~~~~~
<source>:8:13: note:   template argument deduction/substitution failed:
<source>:19:30: error: '(FunctionPointer)functions[0]' is not a valid template argument for type 'void (*)()'
   19 |  wrapper_function<functions[0]>();  // Error?
      |                   ~~~~~~~~~~~^
<source>:19:30: note: it must be the address of a function with external linkage

clang无法通过以下消息进行编译:

<source>:19:2: error: no matching function for call to 'wrapper_function'
        wrapper_function<functions[0]>();  // Error?
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:8:13: note: candidate template ignored: invalid explicitly-specified argument for template parameter 'function'
static void wrapper_function()
            ^
1 error generated.

问题:

wrapper_function<functions[0]>();有效还是无效?

如果不是,我可以做些什么functions[0]作为模板参数传递给wrapper_function吗?我的目标是在编译时使用content构造一个新的函数指针数组{ wrapper_function<functions[0]>, ..., wrapper_function<functions[std::size(functions) - 1]> }


嗯,这很有趣,我认为问题在于您使用的是值(指针)而不是类型。但即使wrapper_function<decltype(functions[0])>()不编译。
CoryKramer

6
似乎可以在C ++ 17中工作...现在可以发现标准语言中的区别...
AndyG

Answers:


5

wrapper_function<functions[0]>();由于以下原因,禁止表达:

14.3.2模板非类型参数[temp.arg.nontype]

非类型,非模板模板参数的模板参数应为以下之一:

[...]

—一个常量表达式(5.19),表示具有静态存储>持续时间和外部或内部链接的对象的地址,或具有外部或内部链接的函数,包括函数模板和函数模板ID,但不包括非静态类成员的表达式(忽略括号)为&id-expression,但如果名称引用函数或数组,则可以省略&;如果相应的模板参数为引用,则应省略;[...]

禁止将指针用作非类型模板参数,而不使用形式,&id因此,基本上可以进行以下操作:

static void test() {}

using FunctionPointer = void(*)();

static constexpr FunctionPointer functions[] = { test };

template <FunctionPointer function>
static void wrapper_function()
{
    function();
}

int main()
{
    test();  // OK
    functions[0]();  // OK

    wrapper_function<test>();  // OK
    wrapper_function<&test>();  // OK
}

并且使用C ++ 14选项编译时,以下代码段将不起作用:

constexpr auto func = &test;
wrapper_function<func>();

当使用C ++ 17选项编译时,您的方法和上面的方法都将起作用:

int main()
{
    test();  // OK
    functions[0]();  // OK

    wrapper_function<test>();  // OK
    wrapper_function<&test>();  // OK
    wrapper_function<func>();  // OK

    wrapper_function<functions[0]>();  // OK
}

现场


正如您在示例中所演示的,不仅形式&id,而且id函数都允许使用,并且常量表达式形式中明确允许使用空指针值。
胡桃

C ++ 17用“ 转换后的常量表达式 ” 代替了它,即它允许链接常量表达式,因此wrapper_function<func>()也可以工作。
rustyx

在我完整编写答案后,Ok将检查并更新答案。Tnx
NutCracker
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.