C++ can';通过一个变量函数传递指向父类中方法的函数指针——编译器错误?
假设您有两个结构,C++ can';通过一个变量函数传递指向父类中方法的函数指针——编译器错误?,c++,inheritance,function-pointers,variadic,compiler-bug,C++,Inheritance,Function Pointers,Variadic,Compiler Bug,假设您有两个结构,Generic\u A和Generic\u BGeneric\u B源自Generic\u A。为什么当Generic\u B尝试访问其父级Generic\u a中的方法时,会生成以下错误: test2.cpp: In function 'int main()': test2.cpp:26: error: no matching function for call to 'case1(void (Generic_A::*)()' 此代码使用gcc版本4.4.6编译,复制了以
Generic\u A
和Generic\u B
Generic\u B
源自Generic\u A
。为什么当Generic\u B
尝试访问其父级Generic\u a
中的方法时,会生成以下错误:
test2.cpp: In function 'int main()':
test2.cpp:26: error: no matching function for call to 'case1(void (Generic_A::*)()'
此代码使用gcc版本4.4.6编译,复制了以下问题:
#include <stdio.h>
struct Generic_A
{
void p1() { printf("%s\n", __PRETTY_FUNCTION__); };
};
struct Generic_B : public Generic_A
{
void p2() { printf("%s\n", __PRETTY_FUNCTION__); };
};
template <class T,class... ARGS>
void case1( void (T::*p)(ARGS...) ) {
printf("%s\n", __PRETTY_FUNCTION__);
}
template <class T>
void case2( void (T::*p)() ) {
printf("%s\n", __PRETTY_FUNCTION__);
}
main()
{
//generates error
case1<Generic_B>(&Generic_B::p1);
//compiles fine
case2<Generic_B>(&Generic_B::p1);
}
发生了什么事 这很棘手,但事实证明g++是正确的 首先,表达式
&泛型B::p1
的类型是void(泛型A::*)()
。编译器使用Generic\u B::
限定其名称查找,并查找Generic\u A
的成员。表达式类型取决于找到的成员的定义,而不是限定id中使用的类型
但这也是合法的
void (Generic_B::*member)() = &Generic_B::p1;
因为存在从void(Generic_A::*)()
到void(Generic_B::*)()
的隐式转换
每当函数模板用作函数调用时,编译器都会经历三个基本步骤(或尝试):
template <class T,class... ARGS>
void case1( void (T::*p)(ARGS...) );
其中,显式模板参数为Generic\u B
,函数参数为Generic\u B::p1
因此,第1步,替换显式模板参数:
void case1( void (Generic_B::*p)(ARGS...) );
步骤2,比较参数类型和参数类型:
参数类型(标准第14.8.2节中的p
)为void(Generic_B::*)(ARGS…
。参数类型(A
)是void(Generic_A::*)()
C++标准(N3485)14.8.2.1p4:
通常,演绎过程试图找到模板参数值,这些值将使演绎的A
与A
相同(在类型A
如上所述转换后)。但是,有三种情况允许存在差异:
- 如果原始
是参考类型,则推导出的p
(即参考引用的类型)可能比转换后的a
更符合cv条件a
- 转换的
可以是另一个指针或指向成员类型的指针,可以通过限定转换(4.4)转换为推导的A
A
- 如果
是一个类,并且p
具有表单简单模板id,则转换后的p
可以是推导出的a
的派生类。同样,如果a
是指向表单简单模板id的类的指针,则转换后的P
可以是指向导出的a
所指向的派生类的指针a
const
/volatile
和/或派生到基的转换,但不考虑指向成员的指针的隐式转换
在案例1
示例中,类型推断失败,且函数不匹配
不幸的是,无法明确指定模板参数pack
ARGS
应替换为空列表。正如您已经发现的那样,您可以通过自己显式地执行必要的成员函数指针转换来实现这一点,即使它在其他方面作为隐式转换是有效的。如果您能够格式化代码以使其更易于阅读,这将有所帮助。例如,很明显,在泛型_A::p1()的定义之后有一个额外的分号。(这不是问题,只是一个观察)在cast示例中缺少一个)
。我想你的意思是把它放在星号后面。我不认为这是一个编译器错误<代码>&Generic_B::p1的类型为void(Generic_A::*)()
,因此需要转换为void(Generic_B:*)()
(根据[conv.mem]/2进行隐式转换)。但是由于这种转换,无法对参数进行类型推断。如果省略显式模板参数,则可以进行类型推断(并且可以正常工作):case2(&Generic_B::p1)
@DyP:但是您可能想调用case1
,而不是case1
。
case1<Generic_B>(&Generic_B::p1)
void case1( void (Generic_B::*p)(ARGS...) );