为什么 type_identity 会有所作为?

why would type_identity make a difference?

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


template <typename ...args_t>
void func(std::function<void(args_t...)> function_, args_t ...args){
    /// do something here
}

void test() {
    func([](int a){ }, 1);
}

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

template <typename T>
struct type_identity {
    using type = T:
};
template <typename T>
using type_identity_t = typename type_identity<T>::type;

void func_wrapped(type_identity_t<std::function<void(args_t...)>> function_, 
                                  args_t ...args> {
    static_assert(std::is_same< std::function<void(args_t...)>,
                                 type_identity_t<std::function<void(args_t...)>>
                              >::value,
                  "different type");
    /// do something here
}

void test() {
    func([](int a){ }, 1);
}

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

error: no matching function for call to ‘func(test()::<lambda(int)>, int)’

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

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

Type deduction does not consider implicit conversions (other than type adjustments listed above): that's the job for overload resolution, which happens later.

后面的代码因为 non-deduced context:

有效

In the following cases, the types, templates, and non-type values that are used to compose P do not participate in template argument deduction, but instead use the template arguments that were either deduced elsewhere or explicitly specified.

  1. The nested-name-specifier (everything to the left of the scope resolution operator ::) of a type that was specified using a qualified-id:

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

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