问题 函数指针作为模板参数


在下面的C ++代码中,该行 bar<func_ptr>(); //does not work 导致编译错误:

#include <iostream>

using namespace std;

void foo(){
    cout<<"Hello world";
};

template<void(*func)()> 
void bar(){
    (*func)();
}

int main() {
    using fun_ptr_type= void(*)();
    constexpr fun_ptr_type func_ptr=&foo;

    bar<&foo>();     //works
    bar<func_ptr>(); //does not work
    return 0;
}

g ++的输出是这样的:

src/main.cpp: In function ‘int main()’:
src/main.cpp:19:16: error: no matching function for call to ‘bar()’
  bar<func_ptr>(); //does not work
                ^
src/main.cpp:10:6: note: candidate: template<void (* func)()> void bar()
 void bar(){
      ^~~
src/main.cpp:10:6: note:   template argument deduction/substitution failed:
src/main.cpp:19:16: error: ‘(fun_ptr_type)func_ptr’ is not a valid template argument for ty
pe ‘void (*)()’
  bar<func_ptr>(); //does not work
                ^
src/main.cpp:19:16: error: it must be the address of a function with external linkage

当我直接传递地址时,我不明白为什么它有效 foo 作为模板参数但是当我通过constexpr时 func_ptr,代码不再编译,即使它完全包含该地址 foo 在编译时。谁可以给我解释一下这个?

编辑:我的g ++版本是

$ g++ --version
g++ (Debian 6.3.0-18+deb9u1) 6.3.0 20170516
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

12393
2017-07-24 15:21


起源

没有gcc8和clang6的repro。 - Baum mit Augen
按预期工作 这里 (C ++ 17)。 - Jarod42
在C ++ 14中出错 演示 - Jarod42
我记得有些变化与指向全局变量和constexpr文字的指针一样,因为C ++ 11以来模板参数有效。但我不记得这是否是这种情况之一,也不知道如何找到它。 - Yakk - Adam Nevraumont
与Jarod42相同的经验。 C ++ 17它有效; C ++ 14吐出错误。 - Eljay


答案:


https://en.cppreference.com/w/cpp/language/template_parameters 它说:

对于函数的指针,有效参数是指向具有链接的函数的指针(或 计算空指针值的常量表达式)。 (直到C ++ 17)。

以来 constexpr fun_ptr_type func_ptr=&foo 不评估为 nullptr 编译时的值,如果你运行它会失败 -std=c++14 要么 -std=c++11

但是,C ++ 17对函数指针非类型模板参数没有这样的要求。它说:

可以与非类型模板参数一起使用的模板参数可以是 任何转换的模板参数类型的常量表达式。 (自C ++ 17起)

(上面有一些例外但不适用于函数指针)。

因此,您提供的代码与 -std=c++17 选项。


10
2017-07-24 15:44