为什么 type_identity 会产生影响?

陈泽霖*_*陈泽霖 12 c++ templates metaprogramming

我知道lambda对象不是std::function对象,所以我知道这是行不通的:

\n
\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}\n
Run Code Online (Sandbox Code Playgroud)\n

但如果我添加一个 type_identity 来包装它,为什么它会起作用呢?

\n
template <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\n
Run Code Online (Sandbox Code Playgroud)\n

据我所知,这两个看起来几乎相同,甚至通过了,这static_assert意味着它们与 .\n 相同std::is_same。\n但编译器并不这么认为。它告诉我,在前一个代码中,lambda 不能匹配任何函数,而后一个可以。

\n

error: no matching function for call to \xe2\x80\x98func(test()::<lambda(int)>, int)\xe2\x80\x99

\n

所以,我的问题是:为什么他们的行为不同?type_identity 隐式做了什么?

\n

son*_*yao 12

前面的代码不起作用,因为在模板参数推导std::function中不会考虑隐式转换(从 lambda 到 ) ,这会导致第一个函数参数的模板参数推导失败。args_tfunction_

类型推导不考虑隐式转换(除了上面列出的类型调整之外):这是稍后发生的重载解析的工作。

后一个代码之所以有效,是因为未推断出上下文

在以下情况下,用于组成P 的类型、模板和非类型值不参与模板实参推导,而是使用在其他地方推导或显式指定的模板实参。

  1. 使用限定 ID 指定的类型的嵌套名称说明符(范围解析运算符 :: 左侧的所有内容):

type_identity第一个函数参数的使用function_被排除在模板参数推导之外;并且args_t可以从第二个函数参数推导出来args,那么它就可以正常工作。

顺便说一句:从 C++20 开始,我们有了std::type_identity.