代码之家  ›  专栏  ›  技术社区  ›  Aidan Cully

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

  •  6
  • Aidan Cully  · 技术社区  · 14 年前

    我当时正在研究 is_class 在Boost中的模板,并遇到一些语法我不容易破译。

        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) void(*)(void) 但我不明白 U:: 修改指针。有人能帮忙吗?

    5 回复  |  直到 14 年前
        1
  •  13
  •   Victor Nicollet    14 年前

    * 指示指针,因为您可以通过写入来访问其内容 *p . U::* U . 您可以通过编写 u.*p pu->*p u 是的实例 U型 ).

    void (U::*)(void) 是指针 致…的成员 U型 这是一个不带参数也不返回值的函数。

    例子:

    class C { void foo() {} };
    
    typedef void (C::*c_func_ptr)(void);
    
    c_func_ptr myPointer = &C::foo;
    
        2
  •  3
  •   GManNickG    14 年前

    你说得对,它类似于函数指针。相反,这是一个指向成员函数的指针,其中成员属于类 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
  •   MBZ    14 年前

    它是指向U类的成员函数的指针。

    但它指向一个U类的成员函数。

        4
  •  3
  •   Peter G.    14 年前

    从U开始,然后由内而外。

        5
  •  0
  •   David Hammen    13 年前

    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. 与第二个重载函数模板相比,它对所有模板参数都是有效的语法,并且函数(如果存在的话)会接受任何抛出的参数,这要归功于它的可变。。。争论(旁白:这让人隐约想起我最喜欢的一行C程序,只要用户输入格式正确,它就可以解决世界上的任何问题。)
    5. 虽然函数模板声明不能作为函数使用,但这些声明可以用于简单的编译时查询,例如关于返回类型的查询。这种查询不需要实际的定义。只需要原型。
    6. 这正是类模板 IsClass 是否定义编译时常量 IsClass<SomeType>::value .

    那你怎么办 IsClass<SomeType>::价值 获取它的值,它在编译时是如何实现的?编译器必须要么理解 sizeof (is_class_tester<T>(0)) 或者放弃尝试。我们需要根据类型 SomeType

    案例1:
    在这种情况下 基类型

    案例2: 基类型
    这就是斯芬娜的用武之地。第一个函数模板声明的语法无效。编译器不能因为SFINAE就放弃这里。它必须不断寻找替代方案,而第二个函数模板声明正好符合要求。唯一可行的函数返回 TypeBiggerThanChar ,定义被省略,但希望是显而易见的。我们想要的就是这个东西的大小。它比一个字符大,所以 IsClass<SomeType>::价值 如果 基类型