lambda 转换为布尔值,而不是推导函数指针类型

lambda converted to bool instead of deducing function-pointer-type

本文关键字:函数 指针 类型 转换 布尔值 lambda      更新时间:2023-10-16

我想为operator<<实现一个重载,允许我调用给定的函数并输出结果。因此,我写了一个重载,但选择了转换为 bool,并且在自己编写函数时,它不会编译。

编辑:知道我不想调用lambda,而是将其传递给函数,在该函数中,应使用默认构造的参数列表调用它。

我已经附加了我的代码:

#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 ptrn" << 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;});

您的问题是模板参数推断仅在传递给test的实际参数上完成。它不会对参数可能转换为的所有可能类型完成。这可能是一个无限的集合,所以这显然是不行的。

因此,模板参数推导是在实际的 lambda 对象上完成的,该对象具有不可描述的类类型。因此,test(T*)的推导失败,因为 lambda 对象不是指针。 显然,T不能从test(bool)推断出来。最后,推导失败test(Ret(*el)(Args...))因为 lambda 对象也不是指向函数的指针。

有几种选择。您甚至可能不需要模板,您可以接受std::function<void(void)>并依赖于它具有模板化构造函数的事实。或者你可以拿一个test(T t)的论点,把它称为t()T现在将推断出实际的 lambda 类型。最花哨的解决方案可能是使用 std::invoke ,并接受模板 vararg 列表。

即使非捕获 lambda 具有到函数指针的隐式转换,函数模板也必须完全匹配才能成功进行演绎,不会执行任何转换。

因此,最简单的解决方法是使用+强制转换

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;
}

现在,您的示例将编译。