为什么这个代码片段适用于C++17而编译器在使用C++11时会抱怨?
为什么这个代码片段适用于 C++17 而编译器在使用 C++11 时会抱怨(即https://godbolt.org/z/71G91P)?此代码片段是否存在任何潜在问题?
#include<iostream>
class ctx
{
public:
int map_create(void*){std::cout << "haha" << std::endl; return 0;};
};
ctx obj;
typedef int (ctx::*ctx_mem_func)(void*);
template <ctx_mem_func func>
int regHelper(void*)
{
((&obj)->*func)(nullptr);
return 0;
}
constexpr ctx_mem_func testFunc = &ctx::map_create;
typedef int(*callBackFunc)(void*);
int reg(callBackFunc)
{
return 0;
}
int main()
{
reg(regHelper<testFunc>);
//But this expression is ok.
reg(regHelper<&ctx::map_create>);
std::cout << "this is a test" << std::endl;
}
以下是使用 c++11(gun 10.0.2) 时的错误信息:
<source>: In function 'int main()':
<source>:30:28: error: no matches converting function 'regHelper' to type 'callBackFunc {aka int (*)(void*)}'
reg(regHelper<testFunc>);
^
<source>:13:5: note: candidate is: template<int (ctx::* func)(void*)> int regHelper(void*)
int regHelper(void*)
^
回答
这是 C++14 和 C++17 之间的区别。简化:
int f();
template<int (&)()> struct S {};
constexpr auto& q = f;
using R = S<q>; // valid in C++17, invalid in C++14
更改是允许对所有非类型模板参数进行常量评估,这意味着现在允许constexpr命名函数(成员函数等)的变量作为 NTTP,而以前只允许函数的实际名称。