为什么 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.
- 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
.
我知道 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.
- 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
.