首页 > 解决方案 > 为什么此代码片段适用于 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++c++11templatesc++17

解决方案


这是 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,而以前只允许函数的实际名称。


推荐阅读