【问题标题】:lambda converted to bool instead of deducing function-pointer-typelambda 转换为 bool 而不是推导函数指针类型
【发布时间】:2018-03-14 18:09:53
【问题描述】:

我想为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 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
}

我使用带有版本标志 -std=c++14 的 gcc 7.3.1。

编辑:错误信息:

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

【问题讨论】:

  • "它不会编译" 显示错误信息

标签: c++ lambda function-pointers ostream template-argument-deduction


【解决方案1】:

您的问题是模板参数推导对传递给test 的实际参数进行。并非对参数可能转换为的所有可能类型都执行此操作。这可能是一个无限集,所以这显然是不行的。

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

有几个选项。您甚至可能不需要模板,您可以接受 std::function&lt;void(void)&gt; 并依赖于它具有模板化构造函数的事实。或者您可以只使用test(T t) 参数并将其称为t()T 现在将推断为实际的 lambda 类型。最奇特的解决方案可能是使用std::invoke,并接受模板可变参数列表。

【讨论】:

  • 但是为什么在使用 cout 的时候会起作用呢?这里使用了哪个重载?为了解决这个问题,我还给bool 重载了一个test(),但是不会用到
  • 没有operator &lt;&lt; 对应std::ostream 和函数指针——至少调试器直接调用std::ostream::operator&lt;&lt;(bool)。但我不知道为什么函数指针会隐式转换为bool。事实上,任何其他函数指针也会打印 true 或 false(当为 NULL 时)。
【解决方案2】:

尽管非捕获 lambda 具有到函数指针的隐式转换,但函数模板必须完全匹配才能成功推导,但不会执行任何转换。

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

int main() {
    std::boolalpha(std::cout);
    std::cout << []{return 5;} << std::endl; // true is outputted
    test(+[]{return 5;}); 
    //   ^
}

【讨论】:

    【解决方案3】:
    template<typename T>
    void test(bool) {
        std::cout << "bool" << std::endl;
    }
    

    不需要模板。事实上,你重载了函数,而不是模板。替换为

    void test(bool) {
         std::cout << "bool" << std::endl;
    }
    

    现在您的示例将编译。

    【讨论】:

      猜你喜欢
      • 2014-10-22
      • 1970-01-01
      • 2023-02-04
      • 2018-10-29
      • 2018-06-15
      • 2013-03-17
      • 1970-01-01
      • 2018-12-28
      • 2021-06-22
      相关资源
      最近更新 更多