我正在研究Boost中is_class
模板的实现,并遇到了一些我无法轻易解读的语法。
template <class U> static ::boost::type_traits::yes_type is_class_tester(void(U::*)(void));
template <class U> static ::boost::type_traits::no_type is_class_tester(...);
如何解读上面的void(U::*)(void)
?我熟悉C,所以它看起来有点类似于void(*)(void)
,但我不明白U::
如何修改指针。有人可以帮忙吗?
由于
答案 0 :(得分:13)
*
表示指针,因为您可以通过编写*p
来访问其内容。 U::*
表示指向类U
成员的指针。您可以通过撰写u.*p
或pu->*p
(其中u
是U
的实例)来访问其内容。
因此,在您的示例中,void (U::*)(void)
是指向<{1}} 成员的指针,该函数不带参数且不返回任何值。
示例:
U
答案 1 :(得分:3)
从U开始,然后在里面工作。
声明的类型是一个指向U类成员函数的指针,它接受void参数并返回void。
答案 2 :(得分:3)
你是对的,它类似于函数指针。相反,这是一个指向成员函数的指针,其中成员属于类U
。
类型的差异是必要的,因为成员函数具有隐式this
指针,因为没有实例就无法调用它们。摆脱模板可能会使它更容易:
struct foo
{
void bar(void);
};
void(*)(void)
不会这样做,因为这无法传达类的实例。相反,我们需要:
void (foo::*)(void)
表示此函数指针需要foo
的实例。
对于它的价值,你可以像这样使用它们:
typedef void (foo::*func_ptr)(void);
foo f;
foo* fp = &f;
func_ptr func = &foo::bar;
(f.*func)();
(fp->*func)();
答案 3 :(得分:3)
它是指向U类成员函数的指针。 它与
非常相似空隙(*)(无效)
但它指向U类的成员函数。
答案 4 :(得分:0)
我打算问同样的问题,但已经有人问了。不幸的是,现有的答案都没有真正回答这个问题。至少不适合我。我不得不把它拼出来。我想提出与OP相同的问题,加上一些问题。我的问题:WTF是这个is_class_tester (void (U::*)(void))
的东西,这个结构如何在SFINAE(替换失败不是错误)的情况下工作?
通过一些简化,Boost使用如下构造:
template <typename U>
char is_class_tester (void (U::*)(void));
template <typename U>
TypeBiggerThanChar is_class_tester (...);
template <typename T>
struct IsClass {
static const bool value = sizeof (is_class_tester<T>(0)) == 1;
};
一些观察结果:
T
是一个类时,两个函数模板中的第一个才有意义。基本类型和指针没有成员函数。第一个声明是非类类型的无效语法。IsClass
用于定义编译时常量IsClass<SomeType>::value
的功能。那么IsClass<SomeType>::value
如何获得它的价值,以及它在编译时如何做到这一点?编译器必须理解sizeof (is_class_tester<T>(0))
或放弃尝试。我们需要根据类型SomeType
是否为类来查看两种情况。
案例1:SomeType
是一个班级
这里两个模板声明都是有效的语法,因此编译器有两个可供选择的候选者。编译器可以而且必须是第一个函数模板,因为选择规则规定可变参数函数在选择中获得最低优先级。此选定函数返回一个char。由于sizeof(char)保证为1,因此IsClass<SomeType>::value
在SomeType
为类的情况下为真。
案例2:SomeType
不是一个班级
这是SFINAE开始的地方。第一个函数模板声明是无效的语法。由于SFINAE,编译器不能只放弃这里。它必须继续寻找替代方案,第二个功能模板声明符合要求。唯一可行的函数返回TypeBiggerThanChar
,定义省略,但希望很明显。我们想要的只是sizeof()这个东西。它比char更大,因此IsClass<SomeType>::value
在SomeType
不是类的情况下将是假的。