双11狂欢大促

盲盒赢 定制羽绒服

开启惊喜盲盒,抽取你的专属好礼

— 惊喜奖品抢先看 —

&&&&*** C++ 2011(MS版本)中 std::bind 的源代码,模版推导出现问题了???--------

hzhxxx hzhxxx 墨衍会员 · AI 创作全网分发 墨衍智能分发 通过墨衍一键同步至各平台 可同步平台 CSDN微信公众号微博知乎掘金百家号博客园抖音小红书 你的文章也可以这样分发 墨衍会员 ¥399起/年,写一次发全网 我也要 + 加入社区
世界钢铁技术头号王国卢森堡


c:\program files\microsoft visual studio 11.0\vc\include\functional
里面,调用 std::bind,里面实际上是调用了 _Bind 的构造函数,构造了一个
_Bind类返回了,我们跟踪类 _Bind 的定义,他是依赖

_VARIADIC_EXPAND_0X(_CLASS_BIND, , , , )
这个宏来定义的。

// for 0-X args
#define _VARIADIC_EXPAND_0X(FUNC, X1, X2, X3, X4) \
_VARIADIC_EXPAND_0(FUNC, X1, X2, X3, X4) \
_VARIADIC_EXPAND_1X(FUNC, X1, X2, X3, X4)

#define _VARIADIC_EXPAND_1X(FUNC, X1, X2, X3, X4) \
_VARIADIC_EXPAND_1(FUNC, X1, X2, X3, X4) \
_VARIADIC_EXPAND_2X(FUNC, X1, X2, X3, X4)

#if _VARIADIC_MAX == 5
#define _VARIADIC_EXPAND_2X _VARIADIC_EXPAND_25

#define _VARIADIC_EXPAND_25(FUNC, X1, X2, X3, X4) \
_VARIADIC_EXPAND_2(FUNC, X1, X2, X3, X4) \
_VARIADIC_EXPAND_3(FUNC, X1, X2, X3, X4) \
_VARIADIC_EXPAND_4(FUNC, X1, X2, X3, X4) \
_VARIADIC_EXPAND_5(FUNC, X1, X2, X3, X4)

最终展开到类定义一级,应应是6个定义,索引从 0~5
#define _VARIADIC_EXPAND_0(FUNC, X1, X2, X3, X4) \
FUNC(_TEM_LIST0, _PAD_LIST0, _RAW_LIST0, , X1, X2, X3, X4)

#define _VARIADIC_EXPAND_1(FUNC, X1, X2, X3, X4) \
FUNC(_TEM_LIST1, _PAD_LIST1, _RAW_LIST1, _COMMA, X1, X2, X3, X4)

#define _VARIADIC_EXPAND_1(FUNC, X1, X2, X3, X4) \
FUNC(_TEM_LIST1, _PAD_LIST1, _RAW_LIST1, _COMMA, X1, X2, X3, X4)

#define _VARIADIC_EXPAND_2(FUNC, X1, X2, X3, X4) \
FUNC(_TEM_LIST2, _PAD_LIST2, _RAW_LIST2, _COMMA, X1, X2, X3, X4)
....
#define _VARIADIC_EXPAND_5(FUNC, X1, X2, X3, X4) \
FUNC(_TEM_LIST5, _PAD_LIST5, _RAW_LIST5, _COMMA, X1, X2, X3, X4)

类似这样的定义,应是6个定义,索引从 0~5
_CLASS_BIND(_TEM_LIST0, _PAD_LIST0, _RAW_LIST0, _COMMA, X1, X2, X3, X4)
_CLASS_BIND(_TEM_LIST1, _PAD_LIST1, _RAW_LIST1, _COMMA, X1, X2, X3, X4)
......
_CLASS_BIND(_TEM_LIST5, _PAD_LIST5, _RAW_LIST5, _COMMA, X1, X2, X3, X4)


template<bool _Forced, class _Ret, class _Fun, _MAX_CLASS_LIST> class _Bind;

#define _CLASS_BIND( \
TEMPLATE_LIST2, PADDING_LIST2, LIST2, COMMA, X1, X2, X3, X4) \
template<bool _Forced, \
class _Ret, \
class _Fun COMMA LIST2(_CLASS_TYPEX)> \
class _Bind<_Forced, _Ret, _Fun, \
LIST2(_TYPEX) COMMA PADDING_LIST2(_NIL_PAD)> \
: public _Add_result_type<_Forced, \
_Has_result_type< \
typename decay<_Fun>::type>::type::value, \
_Ret, \
typename decay<_Fun>::type> \
{...省略里面的定义和实现};


我们展开宏_VARIADIC_EXPAND_0X,实际上应该得到6 个类似
FUNC(_TEM_LIST2, _PAD_LIST2, _RAW_LIST2, _COMMA, X1, X2, X3, X4)
的定义,这样,最后展开,我发现这样会出现6个 _Bind 的模版类定义,
关键的是前面的 template<arg>,里面的 arg 参数个数还不一样,这样应该编译通不过的吧


#define _VARIADIC_EXPAND_ALT_05(FUNC, X1, X2, X3, X4) \
_VARIADIC_EXPAND_ALT_0(FUNC, X1, X2, X3, X4) \
_VARIADIC_EXPAND_ALT_1(FUNC, X1, X2, X3, X4) \
_VARIADIC_EXPAND_ALT_2(FUNC, X1, X2, X3, X4) \
_VARIADIC_EXPAND_ALT_3(FUNC, X1, X2, X3, X4) \
_VARIADIC_EXPAND_ALT_4(FUNC, X1, X2, X3, X4) \

#define _VARIADIC_EXPAND_ALT_2(FUNC, X1, X2, X3, X4) \
FUNC(_TEM_LIST2, _PAD_LIST2, _RAW_LIST2, _COMMA, X1, X2, X3, X4)

我们以 _CLASS_BIND(_TEM_LIST2, _PAD_LIST2, _RAW_LIST2, _COMMA, X1, X2, X3, X4) 为例展开

template<bool _Forced, class _Ret, class _Fun COMMA _RAW_LIST2(_CLASS_TYPEX)> class _Bind<_Forced, _Ret, _Fun,
_RAW_LIST2(_TYPEX) COMMA _PAD_LIST2(_NIL_PAD)> : public _Add_result_type<_Forced,
_Has_result_type<typename decay<_Fun>::type>::type::value, _Ret, typename decay<_Fun>::type> {...省略里面的定义和实现};


#define _RAW_LIST2(MAP) MAP(0) _COMMA MAP(1)

#define _PAD_LIST2 _PAD_LIST0_3
#define _PAD_LIST0_3(MAP) MAP(0) _COMMA MAP(1) _COMMA MAP(2) _COMMA MAP(3)

#define _CLASS_TYPEX(NUM) class _VAR_TYPEX(NUM)
#define _VAR_TYPEX(NUM) _Vx ## NUM ## _t

#define _TYPEX(NUM) _VAR_TYPEX(NUM)

#define _NIL_PAD(NUM) _Nil
// STRUCT _Nil
struct _Nil
{ // empty struct, for unused argument types
};

根据上面的定义,推导出来的结果应该是
_RAW_LIST2(_CLASS_TYPEX) -> _CLASS_TYPEX(0),_CLASS_TYPEX(1) ->
class _VAR_TYPEX(0),class _VAR_TYPEX(1) -> class _Vx0_t,class _Vx1_t

_RAW_LIST2(_TYPEX) -> _TYPEX(0),_TYPEX(1)->_VAR_TYPEX(0),_VAR_TYPEX(1)->_Vx0_t,_Vx1_t

_PAD_LIST2(_NIL_PAD)->_NIL_PAD(0),_NIL_PAD(1)->_Nil,_Nil

这个就是携带两个参数的_Bind 类模版的完整定义
template<bool _Forced, class _Ret, class _Fun, class _Vx0_t,class _Vx1_t>
class _Bind<_Forced, _Ret, _Fun, _Vx0_t,_Vx1_t,_Nil,_Nil> : public _Add_result_type<_Forced,
_Has_result_type<typename decay<_Fun>::type>::type::value, _Ret, typename decay<_Fun>::type> {...省略里面的定义和实现};

很容易推导不携带参数和多个参数的定义
template<bool _Forced, class _Ret, class _Fun>
class _Bind<_Forced, _Ret, _Fun> : public _Add_result_type<_Forced,
_Has_result_type<typename decay<_Fun>::type>::type::value, _Ret, typename decay<_Fun>::type> {...省略里面的定义和实现};

template<bool _Forced, class _Ret, class _Fun, class _Vx0_t,class _Vx1_t,class _Vx2_t>
class _Bind<_Forced, _Ret, _Fun, _Vx0_t,_Vx1_t,_Vx2_t,_Nil,_Nil> : public _Add_result_type<_Forced,
_Has_result_type<typename decay<_Fun>::type>::type::value, _Ret, typename decay<_Fun>::type> {...省略里面的定义和实现};

问题出来了,模版参数个数不一致,不能通过编译啊
template<bool _Forced, class _Ret, class _Fun, _MAX_CLASS_LIST> class _Bind;
template<bool _Forced, class _Ret, class _Fun> class _Bind<_Forced, _Ret, _Fun> : public _Add_result_type<_Forced, _Has_result_type<typename decay<_Fun>::type>::type::value, _Ret, typename decay<_Fun>::type> {...省略里面的定义和实现};
template<bool _Forced, class _Ret, class _Fun, class _Vx0_t,class _Vx1_t> class _Bind<_Forced, _Ret, _Fun, _Vx0_t,_Vx1_t,_Nil,_Nil> : public _Add_result_type<_Forced, _Has_result_type<typename decay<_Fun>::type>::type::value, _Ret, typename decay<_Fun>::type> {...省略里面的定义和实现};
template<bool _Forced, class _Ret, class _Fun, class _Vx0_t,class _Vx1_t,class _Vx2_t> class _Bind<_Forced, _Ret, _Fun, _Vx0_t,_Vx1_t,_Vx2_t,_Nil,_Nil> : public _Add_result_type<_Forced, _Has_result_type<typename decay<_Fun>::type>::type::value, _Ret, typename decay<_Fun>::type> {...省略里面的定义和实现};
...全文

相关推荐

C++获取当前时间精确到毫秒Ms

C++获取当前时间精确到毫秒Ms

fosdick123

Effective Modern C++ 条款34:考虑lambda而非std::bind

无论如何,这样的理解都是值得的,因为你永远不知道何时会在阅读或维护的代码库中遇到。这是可以理解的,但是在这种情况下,改变是更好的,因为在C++11中,在C++14中,通常可以省略标准运算符模板的模板类型实参,因此无需在此处提供。进一步假设,在程序的某个时刻,我们已经确定需要设置一个小时后响30秒的警报器。(答案是传递给bind对象的所有实参都是通过引用传递的,因为此类对象的函数调用运算符使用完美转发。)等简化在C++14中的代码,其中标准后缀基于C++11对用户自定义常量的支持。的调用是通过一个函数指针。

举个栗子2

详解C++11 线程休眠函数

C++ 11之前并未提供专门的休眠函数。c语言的sleep、usleep其实都是系统提供的函数,不同的系统函数的功能还有些差异。 在Windows系统中,sleep的参数是毫秒。 sleep(2*1000); //sleep for 2 seconds 在类Unix系统中,sleep()函数的单位是秒。 sleep(2); //sleep for 2 seconds 从C++11开始,中C++标准库提供了专门的线程休眠函数,使得你的代码可以独立于不同的平台。 std::this_thread::sleep_for std::this_thread::sleep_untill 1. 让线

weixin_38676500

VS Code 配置C++编译环境.docx

VS Code 中配置 C/C++ 编译环境,无需进行tasks.json、launch.json、c_cpp_properties.json 文件的配置

分享技艺

C++获取系统时间 很全面的哦

C++获取系统时间 很全面的哦 C++获取系统时间 很全面的哦

zhanglidn013
评论 19
收藏 已收藏
分享
返回顶部
hzhxxx
C++ 语言 65,214 成员 250,514 内容