“const T *”可以匹配指向自由函数的指针吗?

时间:2013-03-22 19:22:41

标签: c++ c++11 const function-pointers

related question中,它表示没有指向非成员const函数的指针。另外,C ++ 11 8.3.5 / 6说

  

cv-qualifier-seq在函数声明符中的作用与在函数类型之上添加cv-qualification不同。在后一种情况下,cv限定符是   忽略。 [注意:具有cv-qualifier-seq的函数类型不是cv限定类型; 没有符合cv标准的函数类型。 - 后注]

如果我理解正确,这意味着没有非成员const函数。 (虽然这些函数不是常量,但不能按照3.10 / 6进行修改)。特别是,指向const函数的指针是没有意义的。

但是,似乎有些编译器会在类型推导上下文中创建指向const函数的指针。例如,考虑代码:

#include <iostream>

void f() {}

template <typename T> void g(      T*) { std::cout << "non const" << std::endl; }
template <typename T> void g(const T*) { std::cout << "const    " << std::endl; }

int main() {
     g(f);
}

当使用GCC和Intel编译时,代码输出“非常量”,正如我从上面的引用中所期望的那样。但是,使用Clang和Visual Studio编译时输出为“const”。

我的解释是否正确?

更新

在评论之后,我试图澄清我谈论const成员函数。我对非成员函数感兴趣(但同样的参数也可能适用于非静态成员函数)。我也改变了问题标题,使其更精确。

与上述g(f)的解决方案一致,以下行对于GCC和英特尔来说是非法的,但不适用于Clang和Visual Studio

const auto* ptr = &f;

更新2:

我同意Andy Prowl的解释,并选择了他的答案。但是,在此之后,我意识到这个问题是CWG open issue

1 个答案:

答案 0 :(得分:10)

  

如果我理解正确,这意味着没有非成员const函数。 (虽然这些函数不是常量,但不能按照3.10 / 6进行修改)。特别是,指向const函数的指针是没有意义的。

是的,没有const函数这样的东西,并且尝试创建一个忽略,因为你引用了相同的段落。这很重要,因为无论如何创建const函数类型的程序格式不正确(as was the case in C++03);简单地说,它的尝试被忽略了,而是考虑了非const函数类型。

这可能是GCC和ICC无法应用的原因,因为当删除非const重载时,the program does not compile

#include <iostream>

void f() {}

template <typename T> void g( T const*) 
{ 
   std::cout << "const    " << std::endl; 
}

int main() {
     g(f); // ERROR with GCC and ICC, compiles with Clang
}

关于你的解释:

  

当使用GCC和Intel编译时,代码输出“非常量”,正如我从上面的引用中所期望的那样。但是,使用Clang和Visual Studio编译时输出为“const”。我的解释是否正确?

我不相信。据我所知, Clang是对的。

这个结论是基于两个函数模板都可行的事实,因为const限定符在函数类型上被忽略,而一个比另一个更专业。

根据C ++ 11标准的第8.3.5 / 7段,事实上:

  

[...] cv-qualifier-seq在函数声明符中的作用与在顶部添加cv-qualification不同   功能类型。 在后一种情况下,忽略cv限定符。 [...]

这有效地使第二个函数模板可用于解析调用(显然是第一个)。但由于两个函数模板都是可行的,关于重载决策的第13.3.3.1节开始发挥作用:

  

鉴于这些定义,一个可行的函数F1被定义为比另一个可行函数F2更好的函数,如果对于所有参数i,ICSi(F1)不是比ICSi(F2)更差的转换序列,然后

     

- 对于某些参数j,ICSj(F1)是比ICSj(F2)更好的转换序列,或者,如果不是,

     

- 上下文是用户定义转换的初始化(见8.5,13.3.1.5和13.3.1.6)和   从返回类型F1到目标类型的标准转换序列(即,类型的   正在初始化的实体)是比标准转换序列更好的转换序列   F2的返回类型到目标类型。 [...]或者,如果不是那样,

     

- F1是非模板函数,F2是函数模板特化,或者,如果不是,

     

- F1和F2是功能模板专业化,F1的功能模板比F2模板更专业,根据14.5.6.2中描述的偏序规则。

由于第二个函数模板比​​第一个函数模板更专业,因此应通过重载决策选择第二个函数模板。因此, Clang是对的