【问题标题】:Strange template syntax in <functional><functional> 中奇怪的模板语法
【发布时间】:2013-03-06 05:43:36
【问题描述】:

我一直在查看 gcc-4.7.2 中 std::functionstd::bind 的源代码,并且遇到了一些我不理解的用于成员函数指针的语法。

我不明白的是_Maybe_wrap_member_pointer的专业化:

template<typename _Tp, typename _Class>
struct _Maybe_wrap_member_pointer<_Tp _Class::*> // note no comma here
  • 为什么_Tp_Class::*之间没有逗号?

  • 给定成员函数void foo::bar()(在我下面的示例应用程序中),_Tp_Class::* 会在这里解析什么?

下面是我的示例应用程序,它绑定了成员函数指针和对象。 (我已经为成员函数提取了与std::bind specialisations/internals 相关的源代码)

#include <iostream>
#include <functional>

template<typename T>
struct _Maybe_wrap_member_pointer;

template<typename _Tp, typename _Class>
struct _Maybe_wrap_member_pointer<_Tp _Class::*> // <-- I don't understand this
{                                                // why not <_Tp, _Class::*>  
    typedef std::_Mem_fn<_Tp _Class::*> type;    

    static type __do_wrap(_Tp _Class::* __pm)  
    {
        return type(__pm);
    }
};

template<typename _Func, typename... _BoundArgs>
struct _Bind_helper
{
    typedef _Maybe_wrap_member_pointer<typename std::decay<_Func>::type> __maybe_type;

    typedef typename __maybe_type::type __func_type;
    typedef std::_Bind<__func_type(typename std::decay<_BoundArgs>::type...)> type;
};

template<typename _Func, typename... _BoundArgs>
inline 
typename _Bind_helper<_Func, _BoundArgs...>::type
bind(_Func&& __f, _BoundArgs&&... __args)
{
    typedef _Bind_helper<_Func, _BoundArgs...>   __helper_type;
    typedef typename __helper_type::__maybe_type __maybe_type;
    typedef typename __helper_type::type         __result_type;

    return __result_type(__maybe_type::__do_wrap(std::forward<_Func>(__f)),
                                                 std::forward<_BoundArgs>(__args)...);
}

struct foo
{
    void bar()
    {
        std::cout << __func__ << std::endl;
    }
};

int main()
{
    foo f;

    std::function<void()> fun = bind(&foo::bar, f);
    fun();

    exit(0);
}

【问题讨论】:

    标签: c++ templates c++11 std-function stdbind


    【解决方案1】:

    这确实是用于将成员指针类型指定为模板参数的语法。

    假设你有一堂课

    struct Bar
    {
      int n;
    };
    

    那么指向成员Bar::n 的指针必须将其类型声明为int Bar::*

    int Bar::* p = &Bar::n;
    

    请注意,int 指的是指针指向的类型,Bar::* 表示“指向Bar 成员的指针”。

    现在你的例子的功能,

    template<typename _Tp, typename _Class>
    struct _Maybe_wrap_member_pointer<_Tp _Class::*> // note no comma here
    

    接受一个模板参数(只有一个!),它代表_Class 类的成员指针类型,指向_Tp 类型的非静态数据成员。

    这是一个类模板的模板特化,它只有一个模板参数:

    template <typename T>
    struct _Maybe_wrap_member_pointer
    { };
    

    我们可以像这样使用上面的简单类来实例化特化:

    _Maybe_wrap_member_pointer<int Bar::*>
    

    或使用decltype:

    _Maybe_wrap_member_pointer<decltype(&Bar::n)>
    

    在这两种情况下,_Tp 被推导为 int_Class 被推导为 Bar

    【讨论】:

    • 我们可能会补充一点,数据成员类型_Tp 可以是一个定义了operator()() 的类,因此仍然可以调用(尽管不是函数)。 bindfunction 试图解决这个问题。
    • _Tp也可以是函数类型,Tp Class::*构造可以引用指向成员数据的指针指向成员函数的指针
    【解决方案2】:
    • 为什么 _Tp 和 _Class::* 之间没有逗号?

    jogojapan 回答了这部分

    • 给定成员函数 void foo::bar()(在下面我的示例应用程序中),_Tp 和 _Class::* 将在这里解析什么?

    Tp Class::* 等类型可以表示指向成员数据的指针指向成员函数的指针,在后一种情况下,Tp 将是函数类型。

    在您的示例中,_Tp 将是函数类型 void ()_Class 将是 foo

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-03-08
      • 1970-01-01
      • 1970-01-01
      • 2016-01-20
      • 1970-01-01
      • 1970-01-01
      • 2013-09-05
      • 2017-12-06
      相关资源
      最近更新 更多