#c #templates #metaprogramming
Вопрос:
Я знаю, что 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);
}
но почему это сработает, если я добавлю идентификатор типа для его обертывания?
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
.
но компилятор просто так не думает. это сказало мне, что в первом коде лямбда не может соответствовать какой-либо функции, в то время как последняя может.
error: no matching function for call to ‘func(test()::<lambda(int)>, int)’
итак, мой вопрос: почему они ведут себя по-другому? что неявно делал type_identity?
Ответ №1:
Прежний код не работает, потому что неявное преобразование (из лямбда в std::function
) не будет учитываться при вычитании аргумента шаблона, что приводит к ошибке вычитания параметра шаблона из args_t
1-го параметра функции function_
.
Вычет типов не учитывает неявные преобразования (кроме перечисленных выше корректировок типов): это задача по разрешению перегрузки, которая выполняется позже.
Последний код работает из-за не выведенного контекста:
В следующих случаях типы, шаблоны и значения, не относящиеся к типу, которые используются для составления P, не участвуют в выводе аргументов шаблона, а вместо этого используют аргументы шаблона, которые были либо выведены в другом месте, либо явно указаны.
- Спецификатор вложенного имени (все слева от оператора разрешения области ::) типа, указанного с использованием квалифицированного идентификатора:
При использовании type_identity
1-го параметра функции function_
исключается вычет аргумента шаблона; и args_t
может быть выведен из 2-го параметра функции args
, тогда он работает нормально.
КСТАТИ: Начиная с C 20, у нас есть std::type_identity
.