陈泽霖*_*陈泽霖 12 c++ templates metaprogramming
我知道lambda对象不是std::function对象,所以我知道这是行不通的:
\ntemplate <typename ...args_t>\nvoid func(std::function<void(args_t...)> function_, args_t ...args){\n /// do something here\n}\n\nvoid test() {\n func([](int a){ }, 1);\n}\nRun Code Online (Sandbox Code Playgroud)\n但如果我添加一个 type_identity 来包装它,为什么它会起作用呢?
\ntemplate <typename T>\nstruct type_identity {\n using type = T;\n};\ntemplate <typename T>\nusing type_identity_t = typename type_identity<T>::type;\n\ntemplate <typename... args_t>\nvoid func_wrapped(type_identity_t<std::function<void(args_t...)>> function_, \n args_t ...args) {\n static_assert(std::is_same< std::function<void(args_t...)>,\n type_identity_t<std::function<void(args_t...)>>\n >::value,\n "different type");\n /// do something here\n}\n\nvoid test() {\n func_wrapped([](int a){ }, 1);\n}\n\nRun Code Online (Sandbox Code Playgroud)\n据我所知,这两个看起来几乎相同,甚至通过了,这static_assert意味着它们与 .\n 相同std::is_same。\n但编译器并不这么认为。它告诉我,在前一个代码中,lambda 不能匹配任何函数,而后一个可以。
error: no matching function for call to \xe2\x80\x98func(test()::<lambda(int)>, int)\xe2\x80\x99
所以,我的问题是:为什么他们的行为不同?type_identity 隐式做了什么?
\nson*_*yao 12
前面的代码不起作用,因为在模板参数推导std::function中不会考虑隐式转换(从 lambda 到 ) ,这会导致第一个函数参数的模板参数推导失败。args_tfunction_
类型推导不考虑隐式转换(除了上面列出的类型调整之外):这是稍后发生的重载解析的工作。
后一个代码之所以有效,是因为未推断出上下文:
在以下情况下,用于组成P 的类型、模板和非类型值不参与模板实参推导,而是使用在其他地方推导或显式指定的模板实参。
- 使用限定 ID 指定的类型的嵌套名称说明符(范围解析运算符 :: 左侧的所有内容):
type_identity第一个函数参数的使用function_被排除在模板参数推导之外;并且args_t可以从第二个函数参数推导出来args,那么它就可以正常工作。
顺便说一句:从 C++20 开始,我们有了std::type_identity.