Лямбда преобразуется в bool вместо определения типа указателя на функцию
Я хотел реализовать перегрузку для operator<<
это позволило мне вызвать данную функцию и вывести результат. Поэтому я написал перегрузку, но преобразование в bool выбрано, и при написании функции оно не компилируется.
РЕДАКТИРОВАТЬ: Знайте, что я не хочу вызывать лямбда, но вместо этого передать его в функцию, где он должен быть вызван с созданным по умолчанию списком параметров.
Я добавил свой код:
#include <iostream>
template<typename T>
void test(T *) {
std::cout << "ptr" << std::endl;
}
template<typename T>
void test(bool) {
std::cout << "bool" << std::endl;
}
template<typename Ret, typename ...Args>
void test(Ret(*el)(Args...)) {
std::cout << "function ptr\n" << el(Args()...) << std::endl;
}
template<typename Char_T, typename Char_Traits, typename Ret, typename ...Args>
std::basic_ostream<Char_T, Char_Traits>& operator<<(
std::basic_ostream<Char_T, Char_Traits> &str, Ret(*el)(Args...)) {
return str << el(Args()...);
}
int main() {
std::boolalpha(std::cout);
std::cout << []{return 5;} << std::endl; // true is outputted
test([]{return 5;}); // will not compile
}
Я использую gcc 7.3.1 с флагом версии -std=c++14
,
РЕДАКТИРОВАТЬ: сообщение об ошибке:
main.cc: In function ‘int main()’:
main.cc:25:23: error: no matching function for call to ‘test(main()::<lambda()>)’
test([]{return 5;});
^
main.cc:5:6: note: candidate: template<class T> void test(T*)
void test(T *) {
^~~~
main.cc:5:6: note: template argument deduction/substitution failed:
main.cc:25:23: note: mismatched types ‘T*’ and ‘main()::<lambda()>’
test([]{return 5;});
^
main.cc:9:6: note: candidate: template<class T> void test(bool)
void test(bool) {
^~~~
main.cc:9:6: note: template argument deduction/substitution failed:
main.cc:25:23: note: couldn't deduce template parameter ‘T’
test([]{return 5;});
^
main.cc:13:6: note: candidate: template<class Ret, class ... Args> void test(Ret (*)(Args ...))
void test(Ret(*el)(Args...)) {
^~~~
main.cc:13:6: note: template argument deduction/substitution failed:
main.cc:25:23: note: mismatched types ‘Ret (*)(Args ...)’ and ‘main()::<lambda()>’
test([]{return 5;});
3 ответа
Ваша проблема здесь в том, что вычитание аргумента шаблона выполняется только для фактического аргумента, переданного test
, Это сделано не для всех возможных типов, в которые аргумент может быть преобразован. Это может быть бесконечное множество, так что это явно не пойдет.
Итак, Template Argument Deduction выполняется для реального лямбда-объекта, который имеет невероятный тип класса. Таким образом, вычет для test(T*)
терпит неудачу, поскольку лямбда-объект не является указателем. T
не может быть выведено из test(bool)
очевидно. Наконец, вычет не удается для test(Ret(*el)(Args...))
поскольку лямбда-объект также не является указателем на функцию.
Есть несколько вариантов. Вам может даже не понадобиться шаблон, вы можете принять std::function<void(void)>
и полагаться на тот факт, что он имеет шаблонный конструктор. Или вы могли бы просто взять test(T t)
аргумент и назвать его как t()
, T
теперь выведет к фактическому лямбда-типу. Наиболее причудливое решение, вероятно, использует std::invoke
и принятие шаблона vararg list.
Даже если лямбды без захвата имеют неявное преобразование в указатели функций, шаблоны функций должны точно совпадать, чтобы вывод был успешным, преобразования не будут выполняться.
Следовательно, самое простое решение - заставить преобразование +
int main() {
std::boolalpha(std::cout);
std::cout << []{return 5;} << std::endl; // true is outputted
test(+[]{return 5;});
// ^
}
template<typename T>
void test(bool) {
std::cout << "bool" << std::endl;
}
Шаблон не нужен. На самом деле вы перегружаете функции, а не шаблоны. Замени это
void test(bool) {
std::cout << "bool" << std::endl;
}
Теперь ваш образец будет скомпилирован.