void(U :: *)(void)是什么意思?

时间:2010-07-19 12:00:29

标签: c++ templates

我正在研究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::如何修改指针。有人可以帮忙吗?

由于

5 个答案:

答案 0 :(得分:13)

*表示指针,因为您可以通过编写*p来访问其内容。 U::*表示指向类U成员的指针。您可以通过撰写u.*ppu->*p(其中uU的实例)来访问其内容。

因此,在您的示例中,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;
};

一些观察结果:

  1. 这些功能模板实际上不是功能模板。它们只是一对重载函数模板的前向声明。从不定义函数模板本身。看到这是如此并理解其如何工作而不需要定义模板是理解这个结构的关键要素之一。
  2. 谈到如何使用这个第一个功能模板的答案错过了船。您不能使用此功能模板,因为它的定义不存在。
  3. 请注意,由于这个神秘的参数,只有类型T是一个类时,两个函数模板中的第一个才有意义。基本类型和指针没有成员函数。第一个声明是非类类型的无效语法。
  4. 对比第二个重载函数模板,它是所有模板参数的有效语法,并且函数(如果它存在)将由于其variadic ...参数而将任何参数抛出。 (旁白:这模糊地让人想起我最喜欢的单行C程序,它可以解决世界上任何问题,给出正确格式化的用户输入。)
  5. 虽然函数模板声明不能用作函数,但声明可用于简单的编译时查询,例如有关返回类型的查询。这种查询不需要实际定义。只需要原型。
  6. 这正是类模板IsClass用于定义编译时常量IsClass<SomeType>::value的功能。
  7. 那么IsClass<SomeType>::value如何获得它的价值,以及它在编译时如何做到这一点?编译器必须理解sizeof (is_class_tester<T>(0))或放弃尝试。我们需要根据类型SomeType是否为类来查看两种情况。

    案例1:SomeType是一个班级 这里两个模板声明都是有效的语法,因此编译器有两个可供选择的候选者。编译器可以而且必须是第一个函数模板,因为选择规则规定可变参数函数在选择中获得最低优先级。此选定函数返回一个char。由于sizeof(char)保证为1,因此IsClass<SomeType>::valueSomeType为类的情况下为真。

    案例2:SomeType不是一个班级 这是SFINAE开始的地方。第一个函数模板声明是无效的语法。由于SFINAE,编译器不能只放弃这里。它必须继续寻找替代方案,第二个功能模板声明符合要求。唯一可行的函数返回TypeBiggerThanChar,定义省略,但希望很明显。我们想要的只是sizeof()这个东西。它比char更大,因此IsClass<SomeType>::valueSomeType不是类的情况下将是假的。