std::function对象比较的问题

 以VS2019 function、bind源码为例分析

Demo code 1:

double a1(double tmp) { printf("This is a1.\n"); return tmp; }
double b1(double fee, int d) { printf("This is b1: fee:%f_d:%d\n", fee, d);return fee; }

#define FUNC_A1 a1
#define BIND_FUNC_B1(d) bind(b1, placeholders::_1, d)

function<double(double)> func_a1 = FUNC_A1;
function<double(double)> func_a2 = FUNC_A1;
function<double(double)> func_b1 = BIND_FUNC_B1(2);
function<double(double)> func_b2 = BIND_FUNC_B1(2);

问题描述:

根据功能需求,想要判断func_a1、func_a2与func_b1是否相等,但是目前function没有直接“==”的重载,无法直接比较;

问题点1:使用function::target获取function中保存的函数指针,通过函数指针来进行判断实现对应功能。具体实现如下:

If(func_a1.target<double(*)(double)>() == func_a2.target<double(*)(double)>()))
{
//do someting1
}
If(func_a2.target<double(*)(double)>() != func_b1.target<double(*)(double)>()))
{
//do someting2
}

出现bug:func_a1.target<double(*)(double)> == func_a2.target<double(*)(double)>为false,无法进入执行do something1。

调查发现std::function::target获取的是一个保存函数指针的二级指针,想要获得函数指针的值,需要通过*(func_a1.target<double(*)(double)>),即:

if(*(func_a1.target<double(*)(double)>()) == *(func_a2.target<double(*)(double)>()))
{
    //do someting1
}
if(*(func_a2.target<double(*)(double)>()) != *(func_b1.target<double(*)(double)>()))
{
    //do someting2
}

问题点2:运行程序后,出现异常,查看log发现,do someting1已经执行,但是没有继续执行do someting2,发现是由于func_b1.target<double(*)(double)>)为nullptr,*(nullptr)导致的程序异常。

查看std::function中关于target的定义,func_b1.target<double(*)(double)>实际调用函数过程如下:

//1.class function

template <class _Fx>
_NODISCARD _Fx* target() noexcept {
    return reinterpret_cast<_Fx*>(const_cast<void*>(this->_Target(typeid(_Fx))));
}

//2.class _Func_class

再看this->_Target()先通过_Getimpl()获取存储在_Mystorage._Ptrs最后一位的指针,即function对象的地址,由于对应的function对象func_b1已经实例,所以此处_Getimpl()不为空,继续通过_Getimpl()->_Target获取类型为_Info的函数指针;

->在创建function对象时,会申请8*8大小的_Mystorage空间作为备用,其中函数对象的指针存储在最后一个元素_Mystorage._Ptrs[7]中。

constexpr int _Small_object_num_ptrs = 6 + 16 / sizeof(void*);//等于8

_Ptrt* _Getimpl() const noexcept {         
    return _Mystorage._Ptrs[_Small_object_num_ptrs-1];
}

const void* _Target(const type_info& _Info) const noexcept {
    return _Getimpl() ? _Getimpl()->_Target(_Info) : nullptr;
}

这里通过监视器查看_Info的具体类型为“.P6ANN@Z”,这是经过解码后的类型,对应的原类型为<double(*)(double)>

名称

类型

_Info

{_Data={_UndecoratedName=0x0000000000000000 <NULL> _DecoratedName=0x00007ff666506280 ".P6ANN@Z" } }

const type_info &

//3.class _Func_base

判断_Target_type()类型和传入的_Info类型是否相同

virtual const type_info& _Target_type() const noexcept override {
    return typeid(_Callable);//_Callable即为func_b1 = BIND_FUNC_B1(2)的类型信息
}
bool operator==(const type_info& _Other) const noexcept
{
    return __std_type_info_compare(&_Data, &_Other._Data) == 0;
}
//这里是type_info类重载的“==”
const void* _Target(const type_info& _Info) const noexcept {
    return _Target_type() == _Info ? _Get() : nullptr;
}

//4.class _Func_impl_no_alloc

如果类型相等,返回保存的函数指针或bind类型std::_Binder的对象指针。

template <class _Ty>

_NODISCARD constexpr _Ty* addressof(_Ty& _Val) noexcept {

    return __builtin_addressof(_Val);//获取_Val地址

}   
virtual const void* _Get() const noexcept override {

    return _STD addressof(_Callee);

}

问题出在批注3的operator==中,这里查看类型分别为:“class std::_Binder<...>”和“.P6ANN@Z

名称

类型

&_Data

MyTestCSDN.exe!0x00007ff6665061c8 {_UndecoratedName=0x000002680e344f60 "class std::_Binder<struct std::_Unforced,double (__cdecl&)(double,int),struct std::_Ph<1> const & __ptr64,int>" ...}

__std_type_info_data *

&_Other._Data

MyTestCSDN.exe!0x00007ff666506278 {_UndecoratedName=0x0000000000000000 <NULL> _DecoratedName=0x00007ff666506280 ".P6ANN@Z" }

const __std_type_info_data *

可以看到,这两种类型并不相同,这也是导致target返回nullptr的根本原因。

实际上“.P6ANN@Z”对应的就是double(*)(double)一个double(double)类型的函数指针,而function内部存储的_Callable的类型是我们在给func_b1赋值的BIND_FUNC_B1(2)的类型,也即bind(b1, placeholders::_1, 2)的类型。问题点已经确定—在使用std::function::target的时候传入的类型不正确导致获取的指针为空,那么现在我们只需要给target传入std::_Binder的类型,似乎问题就可以解决了。

Demo code 2:

func_b1.target<typeid(BIND_FUNC_B1(2))>();

func_b1.target<func_b1.target_type().name()>();

问题点3:

这两条语句都无法编译通过,错误信息如下:

C++ error C2672: “std::function<double (double)>::target”: 未找到匹配的重载函数,看起来target并不支持bind类型的直接使用;

考虑使用如下方法解决:

template<typename T, typename Fn>
T* get_target_new(std::function<Fn>& f, T)
{
    return f.template target<T>();
}

auto p_func_b1_target = get_target_new(func_b1, BIND_FUNC_B1(2));
(*p_func_b1_target)(1.2);
if (*(func_a2.target<double(*)(double)>()) != *(p_func_b1_target))
{
    //do someting2
}

通过一个target的函数模板来实现对bind类型的参数传入,从而获得类型为*std::_Binder的指针,通过这个指针我们可以实现对原bind类型对象的调用。然后尝试对指针进行比较,出现编译错误:

C++ error C2446: “!=”: 没有从“T *”到“_Fx *”的转换;

以及软件中的提示信息:

查看std::_Binder源码,发现类中没有对==运算符进行重载,所以无法对std::_Binder对象直接进行比较;同时发现,在调用bind时,会调用std::_Binder的构造函数,并且将传入的参数组合成一个_Mypair的成员变量进行存储,但是此变量为私有的,无法通过引用这个变量来进行各个参数的比较;由于类型问题,也无法对std::_Binder进行类型转换等操作。

bind相关源码如下:

//1.bind函数

template <class _Fx, class... _Types>

_NODISCARD _CONSTEXPR20 _Binder<_Unforced, _Fx, _Types...> bind(_Fx&& _Func, _Types&&... _Args) {

    return _Binder<_Unforced, _Fx, _Types...>(_STD forward<_Fx>(_Func), _STD forward<_Types>(_Args)...);

}

//2._Binder类

class _Binder : public _Binder_result_type<_Ret, _Fx>::type { // wrap bound callable object and arguments

private:
    using _Seq    = index_sequence_for<_Types...>;
    using _First  = decay_t<_Fx>;
    using _Second = tuple<decay_t<_Types>...>;
    _Compressed_pair<_First, _Second> _Mypair;
    //将多个参数组合成一个私有的成员变量

public:
    constexpr explicit _Binder(_Fx&& _Func, _Types&&... _Args)
        : _Mypair(_One_then_variadic_args_t{}, _STD forward<_Fx>(_Func), _STD forward<_Types>(_Args)...) {}

#define _CALL_BINDER                                                                  \
    _Call_binder(_Invoker_ret<_Ret>{}, _Seq{}, _Mypair._Get_first(), _Mypair._Myval2, \
        _STD forward_as_tuple(_STD forward<_Unbound>(_Unbargs)...))

    template <class... _Unbound>
    _CONSTEXPR20 auto operator()(_Unbound&&... _Unbargs) noexcept(noexcept(_CALL_BINDER)) -> decltype(_CALL_BINDER) {
        return _CALL_BINDER;

    }

    template <class... _Unbound>
    _CONSTEXPR20 auto operator()(_Unbound&&... _Unbargs) const noexcept(noexcept(_CALL_BINDER))
        -> decltype(_CALL_BINDER) {
        return _CALL_BINDER;
    }

#undef _CALL_BINDER
};
template <class _Other1, class... _Other2>
constexpr _Compressed_pair(_One_then_variadic_args_t, _Other1&& _Val1, _Other2&&... _Val2)
  noexcept(conjunction_v<
    is_nothrow_constructible<_Ty1, _Other1>, 
    is_nothrow_constructible<_Ty2, Other2...>>)
      : _Ty1(_STD forward<_Other1>(_Val1)), _Myval2(_STD forward<_Other2>(_Val2)...) {}

1)_One_then_variadic_args_t:第一个参数构造第一个参数,剩余参数构造第二个参数—para1:&b1,
para2:tuple(placeholders::_1, 2)
2)noexcept:运算符进行编译时检查,若表达式声明为不抛出任何异常则返回true;
3)conjunction_v:检查给定类型_Ty1是否是带有参数集_Other1的可构造类型,如果可构造,为true,可通过这个它进行检查避免异常发生;
4)is_nothrow_constructible:判断是否可以直接从_Other1到_Ty1进行初始化, 并别没有异常
 

综上所述:

  目前无法实现对function不同类型对象的比较,至于文中最开始提到的Demo code1所对应的问题,提出以下几种解决方案:

Demo code 1:

double a1(double tmp) { printf("This is a1.\n"); return tmp; }
double b1(double fee, int d) { printf("This is b1: fee:%f_d:%d\n", fee, d);return fee; }

#define FUNC_A1 a1
#define BIND_FUNC_B1(d) bind(b1, placeholders::_1, d)

function<double(double)> func_a1 = FUNC_A1;
function<double(double)> func_a2 = FUNC_A1;
function<double(double)> func_b1 = BIND_FUNC_B1(2);
function<double(double)> func_b2 = BIND_FUNC_B1(2);
  1. 将double a1(double tmp)改为double a1(double tmp, int n),将函数类型统一,进而保证function类型的统一function<double(double, int)>,这样在进行比较时就可以使用target来获取函数指针进行判断了。
  2. 将double b1(double fee, int d)改为double b(double fee){ return b1(fee, 2); },这样可以保证function类型统一为function<double(double)>,但是多进行了一次函数调用,会增加内存开销。
  3. 在调用bind操作的时候,增加对bind相关参数的记录,可以实现各种类型的function对象的比较。
  4. 重构标准库中的function、_Binder类,增加对==的重载,或将保存函数指针的成员变量公有化。

--------------------------------------------------------------------------------------

另外:

在调查过程中,为了更好的解决问题,还对function和bind的源码及实现过程进行了了解,并总结如下,如果感兴趣,可以继续查看下面内容。

以下面代码为例:

double b1(double fee, int d) { printf("This is b1: fee:%f_d:%d\n", fee, d);return fee; }
#define BIND_FUNC_B1(d) bind(b1, placeholders::_1, d)
function<double(double)> func_b1 = BIND_FUNC_B1(2);

//一、构造function对象,并初始化

//1.首先是前面介绍过的bind,调用后返回_Binder类型的变量

template <class _Fx, class... _Types>
_NODISCARD _CONSTEXPR20 _Binder<_Unforced, _Fx, _Types...> bind(_Fx&& _Func, _Types&&... _Args) {
    return _Binder<_Unforced, _Fx, _Types...>(_STD forward<_Fx>(_Func), _STD forward<_Types>(_Args)...);
}

//2.调用_Func_class父类构造函数进行初始化,并初始化函数对象指针为nullptr

_Func_class() noexcept {
    _Set(nullptr);
}

//3.在类中定义了一个_Storage类型的大小为_Small_object_num_ptrs = 8个指针大小的_Mystorage备用空间,并且将最末位指针(存储_Func_base->this指针的位置)赋值为nullptr,进行初始化; 

constexpr int _Small_object_num_ptrs = 6 + 16 / sizeof(void*);
union _Storage { // storage for small objects (basic_string is small)
    max_align_t _Dummy1; // for maximum alignment
    char _Dummy2[_Space_size]; // to permit aliasing
    _Ptrt* _Ptrs[_Small_object_num_ptrs]; // _Ptrs[_Small_object_num_ptrs - 1] is reserved
};

_Storage _Mystorage;
enum { _EEN_IMPL = _Small_object_num_ptrs - 1 }; // helper for expression evaluator
_Ptrt* _Getimpl() const noexcept { // get pointer to object
    return _Mystorage._Ptrs[_Small_object_num_ptrs - 1];
}

void _Set(_Ptrt* _Ptr) noexcept { // store pointer to object
    _Mystorage._Ptrs[_Small_object_num_ptrs - 1] = _Ptr;
}

//4.再调用function子类构造函数

function(_Fx _Func) {
    this->_Reset(_STD move(_Func));
}

//5.调用_Reset为function对象申请空间    

disjunction_v<para1, para2, para3>:判断para1,para2,para3,其中有一个为true即为true,分别判断是否为/成员指针/函数指针/function对象

//检查_Val是否为可用类型
template <class _Ty>
bool _Test_callable(const _Ty& _Arg) noexcept { 
    if constexpr (_Testable_callable_v<_Ty>)
    {
        return !!_Arg;
    } else {
        return true;
    }
}
template <class _Ty>_INLINE_VAR constexpr bool _Testable_callable_v =
disjunction_v<is_pointer<_Ty>, _Is_specialization<_Ty, function>, is_member_pointer<_Ty>>;

//将_Val赋值到_Func_impl_no_alloc类型中的_Callee变量中
_Func_impl_no_alloc(_Other&&_Val) : _Callee(_STD forward<_Other>(_Val)) {}

template <class _Fx>
void _Reset(_Fx&& _Val) { // store copy of _Val
    if (!_Test_callable(_Val)) { // null member pointer/function pointer/std::function
        return; // already empty
    }
    
    using _Impl = _Func_impl_no_alloc<decay_t<_Fx>, _Ret, _Types...>;
    //这里判断_Impl的大小,如果大于指定大小(7*8=56),则申请的空间为_Mystorage
    if constexpr (_Is_large<_Impl>) {
        // dynamically allocate _Val
        _Set(_Global_new<_Impl>(_STD forward<_Fx>(_Val)));
    } else {
        // store _Val in-situ
        _Set(::new (static_cast<void*>(&_Mystorage)) _Impl(_STD forward<_Fx>(_Val)));
    }
}

//6.调用_Set将function对象的指针存储在最后一位

void _Set(_Ptrt* _Ptr) noexcept { // store pointer to object
    _Mystorage._Ptrs[_Small_object_num_ptrs - 1] = _Ptr;
}

//二、调用function对象

//1.operator()实现调用function对象

//_Do_call->_Call->invoke(_Functor)

判断_Mystorage._Ptrs[7]中存储的函数对象指针是否为空 ,为空抛出异常 

_Ptrt* _Getimpl() const noexcept {         
    return     
    _Mystorage._Ptrs[_Small_object_num_ptrs - 1];
}
bool _Empty() const noexcept {
    return !_Getimpl();
}

_Ret operator()(_Types... _Args) const {
    if (_Empty()) {
        _Xbad_function_call();//抛出异常
    }

    const auto _Impl = _Getimpl();
    return _Impl->_Do_call(_STD forward<_Types>(_Args)...);
}

//2. 调用_Invoker_ret<_Rx>::_Call实现函数调用

virtual _Rx _Do_call(_Types&&... _Args) override { // call wrapped function
    return _Invoker_ret<_Rx>::_Call(_Callee, _STD forward<_Types>(_Args)...);
}

//3._Invoker_ret<_Rx>::_Call实际调用的是invoke

_Is_nothrow_invocable_r<_Rx>::value:确定是否可以使用参数_Vals调用_Func,生成可转换为_RX的结果,并且已知该调用(包括参数和结果的转换)不会引发任何异常。
检查invoke调用是否发生异常。

template <class _Rx>
struct _Invoker_ret<_Rx, false> { // selected for all _Rx other than cv void and _Unforced
    template <class _Fx, class... _Valtys>
    static _CONSTEXPR20 _Rx _Call(_Fx&& _Func, _Valtys&&... _Vals) noexcept(_Select_invoke_traits<_Fx,
        _Valtys...>::template _Is_nothrow_invocable_r<_Rx>::value) { // INVOKE, implicitly converted to _Rx
        return _STD invoke(static_cast<_Fx&&>(_Func), static_cast<_Valtys&&>(_Vals)...);
    }
};

//4.根据_Invoker1<_Callable, _Ty1>中存储的_Strategy类型,选择具体调用的分支

template <class _Callable, class _Ty1, class... _Types2>
_CONSTEXPR17 auto invoke(_Callable&& _Obj, _Ty1&& _Arg1, _Types2&&... _Args2) noexcept(
    noexcept(_Invoker1<_Callable, _Ty1>::_Call(
        static_cast<_Callable&&>(_Obj), static_cast<_Ty1&&>(_Arg1), static_cast<_Types2&&>(_Args2)...)))
    -> decltype(_Invoker1<_Callable, _Ty1>::_Call(
        static_cast<_Callable&&>(_Obj), static_cast<_Ty1&&>(_Arg1), static_cast<_Types2&&>(_Args2)...)) {
//---------------------------------------
/*调用的是_Functor这里
此处_Obj(就是前面提到的_Callee)为:bind(0x00007ff6da3514b5{MyTestCSDN.exe!b1(double,int)}, _1, 0x00000002)
_Arg1为:1.2300000000000000
实际上就相当于调用了bind(b1,1.23,2)->b1(1.23,2)*/
    if constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Functor) {
        return static_cast<_Callable&&>(_Obj)(static_cast<_Ty1&&>(_Arg1), static_cast<_Types2&&>(_Args2)...);
//---------------------------------------
    } else if constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmf_object) {
        return (static_cast<_Ty1&&>(_Arg1).*_Obj)(static_cast<_Types2&&>(_Args2)...);
    } else if constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmf_refwrap) {
        return (_Arg1.get().*_Obj)(static_cast<_Types2&&>(_Args2)...);
    } else if constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmf_pointer) {
        return ((*static_cast<_Ty1&&>(_Arg1)).*_Obj)(static_cast<_Types2&&>(_Args2)...);
    } else if constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmd_object) {
        return static_cast<_Ty1&&>(_Arg1).*_Obj;
    } else if constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmd_refwrap) {
        return _Arg1.get().*_Obj;
    } else {
        static_assert(_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmd_pointer, "bug in invoke");
        return (*static_cast<_Ty1&&>(_Arg1)).*_Obj;
    }
}

//5.调用bind的operator(),并且指定返回类型为_CALL_BINDER
将operator()入参组合成一个元组,类似于pair/make_pair

1)获取临时实例_Invoker_ret<_Ret>{},为了后续_Invoker_ret<_Ret>::_Call使用;
2)构造临时参数序列,为了后续使用_Ix, _Jx-1;
3)_Mypair的第一个参数—obj;
4)_Mypair的第二个参数—多个参数构成的tuple(placeholders::_1,d(int))
5)通过forward_as_tuple将operator传入的参数组合成tuple(1.23)

//6.调用_Call_binder实际调用的是_Call

_Call_binder->_Call->invoke(_Functor)
1)get<_Ix>(_Tpl):从std::bind绑定的tuple中获取第_Ix个对象(后面的...说明是可变参数,取第1个、第2个、第I个_Tpl的元素)
2)_STD move(_Ut):对延迟调用时非绑定传入的参数组成的tuple(12中的forward_as_tuple),右值转换传入。

template <class _Ret, size_t... _Ix, class _Cv_FD, class _Cv_tuple_TiD, class _Untuple>
_CONSTEXPR20 auto _Call_binder(_Invoker_ret<_Ret>, index_sequence<_Ix...>, _Cv_FD& _Obj, _Cv_tuple_TiD& _Tpl,
    _Untuple&& _Ut) noexcept(noexcept(_Invoker_ret<_Ret>::_Call(_Obj,
    _Fix_arg(_STD get<_Ix>(_Tpl), _STD move(_Ut))...)))
    -> decltype(_Invoker_ret<_Ret>::_Call(_Obj, _Fix_arg(_STD get<_Ix>(_Tpl), _STD move(_Ut))...)) {
    // bind() and bind<R>() invocation
    return _Invoker_ret<_Ret>::_Call(_Obj, _Fix_arg(_STD get<_Ix>(_Tpl), _STD move(_Ut))...);
}

//7._Fix_arg重新绑定_Tpl(placeholders::_1,d(2))和_Ut(1.23)为(1.23,2)

//这里主要使用了3和4

template <class _Cv_TiD,
bool = _Is_specialization_v<remove_cv_t<_Cv_TiD>, reference_wrapper>,
bool = is_bind_expression_v<_Cv_TiD>,
int = is_placeholder_v<_Cv_TiD>>
struct _Select_fixer;

//1)wrap类型:通过_Is_specialization_v推断是一个wrap引用,比如智能指针,就返回它的get方法。
template <class _Cv_TiD>
struct _Select_fixer<_Cv_TiD, true, false, 0> { // reference_wrapper fixer
    template <class _Untuple>
    static constexpr auto _Fix(_Cv_TiD& _Tid, _Untuple&&) noexcept -> typename _Cv_TiD::type& {
        // unwrap a reference_wrapper
        return _Tid.get();
    }
};
//2)内嵌_Binder类型:通过is_bind_expression_v推断是bind递归调用bind(bind)
template <class _Cv_TiD>
struct _Select_fixer<_Cv_TiD, false, true, 0> { // nested bind fixer
    template <class _Untuple, size_t... _Jx>
    static constexpr auto _Apply(_Cv_TiD& _Tid, _Untuple&& _Ut, index_sequence<_Jx...>) noexcept(
        noexcept(_Tid(_STD get<_Jx>(_STD move(_Ut))...))) -> decltype(_Tid(_STD get<_Jx>(_STD move(_Ut))...)) {
        // call a nested bind expression
        return _Tid(_STD get<_Jx>(_STD move(_Ut))...);
    }

    template <class _Untuple>
    static constexpr auto _Fix(_Cv_TiD& _Tid, _Untuple&& _Ut) noexcept(
        noexcept(_Apply(_Tid, _STD move(_Ut), make_index_sequence<tuple_size_v<_Untuple>>{})))
        -> decltype(_Apply(_Tid, _STD move(_Ut), make_index_sequence<tuple_size_v<_Untuple>>{})) {
        // call a nested bind expression
        return _Apply(_Tid, _STD move(_Ut), make_index_sequence<tuple_size_v<_Untuple>>{});
    }

};
3)普通类型的值:直接返回绑定的参数。
template <class _Cv_TiD>
struct _Select_fixer<_Cv_TiD, false, false, 0> { // identity fixer
    template <class _Untuple>
    static constexpr _Cv_TiD& _Fix(_Cv_TiD& _Tid, _Untuple&&) noexcept {
        // pass a bound argument as an lvalue (important!)
        return _Tid;
    }
};
4)占位符类型的值:第n个占位符对应的就是_Ut中第<_Jx-1>个的值。
template <class _Cv_TiD, int _Jx>
struct _Select_fixer<_Cv_TiD, false, false, _Jx> { // placeholder fixer
    static_assert(_Jx > 0, "invalid is_placeholder value");
    template <class _Untuple>
    static constexpr auto _Fix(_Cv_TiD&, _Untuple&& _Ut) noexcept
        -> decltype(_STD get<_Jx - 1>(_STD move(_Ut))) { // choose the Jth unbound argument (1-based indexing)
        return _STD get<_Jx - 1>(_STD move(_Ut));
    }
};

template <class _Cv_TiD, class _Untuple>
constexpr auto _Fix_arg(_Cv_TiD& _Tid, _Untuple&& _Ut) noexcept(
    noexcept(_Select_fixer<_Cv_TiD>::_Fix(_Tid, _STD move(_Ut))))
    -> decltype(_Select_fixer<_Cv_TiD>::_Fix(_Tid, _STD move(_Ut))) { // translate an argument for bind
    return _Select_fixer<_Cv_TiD>::_Fix(_Tid, _STD move(_Ut));
}

//8.调用_Call实际调用的是invoke

template <>
struct _Invoker_ret<_Unforced, false> { // selected for _Rx being _Unforced
    template <class _Fx, class... _Valtys>
    static _CONSTEXPR20 auto _Call(_Fx&& _Func, _Valtys&&... _Vals) noexcept(
        _Select_invoke_traits<_Fx, _Valtys...>::_Is_nothrow_invocable::value)
        -> decltype(_STD invoke(static_cast<_Fx&&>(_Func), static_cast<_Valtys&&>(_Vals)...)) { // INVOKE, unchanged
        return _STD invoke(static_cast<_Fx&&>(_Func), static_cast<_Valtys&&>(_Vals)...);
    }
};

//9.根据_Invoker1<_Callable, _Ty1>中存储的_Strategy类型,选择具体调用的分支

template <class _Callable, class _Ty1, class... _Types2>
_CONSTEXPR17 auto invoke(_Callable&& _Obj, _Ty1&& _Arg1, _Types2&&... _Args2) noexcept(
    noexcept(_Invoker1<_Callable, _Ty1>::_Call(
        static_cast<_Callable&&>(_Obj), static_cast<_Ty1&&>(_Arg1), static_cast<_Types2&&>(_Args2)...)))
    -> decltype(_Invoker1<_Callable, _Ty1>::_Call(
        static_cast<_Callable&&>(_Obj), static_cast<_Ty1&&>(_Arg1), static_cast<_Types2&&>(_Args2)...)) {
//---------------------------------------
/*调用的是_Functor这里
此处_Obj(就是前面提到的_Callee)为:bind(0x00007ff6da3514b5{MyTestCSDN.exe!b1(double,int)}, _1, 0x00000002)
_Arg1为:1.2300000000000000
实际上就相当于调用了bind(b1,1.23,2)->b1(1.23,2)*/
    if constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Functor) {
        return static_cast<_Callable&&>(_Obj)(static_cast<_Ty1&&>(_Arg1), static_cast<_Types2&&>(_Args2)...);
//---------------------------------------
    } else if constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmf_object) {
        return (static_cast<_Ty1&&>(_Arg1).*_Obj)(static_cast<_Types2&&>(_Args2)...);
    } else if constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmf_refwrap) {
        return (_Arg1.get().*_Obj)(static_cast<_Types2&&>(_Args2)...);
    } else if constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmf_pointer) {
        return ((*static_cast<_Ty1&&>(_Arg1)).*_Obj)(static_cast<_Types2&&>(_Args2)...);
    } else if constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmd_object) {
        return static_cast<_Ty1&&>(_Arg1).*_Obj;
    } else if constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmd_refwrap) {
        return _Arg1.get().*_Obj;
    } else {
        static_assert(_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmd_pointer, "bug in invoke");
        return (*static_cast<_Ty1&&>(_Arg1)).*_Obj;
    }
}

  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值