无法从lambda函数推断出模板参数std :: function [英] Failure to deduce template argument std::function from lambda function

查看:81
本文介绍了无法从lambda函数推断出模板参数std :: function的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在探索C ++模板时,我偶然发现了以下代码中的示例:

While exploring templates in C++, I stumbled upon the example in the following code:

#include <iostream>
#include <functional>

template <typename T>
void call(std::function<void(T)> f, T v)
{
    f(v);
}

int main(int argc, char const *argv[])
{
    auto foo = [](int i) {
        std::cout << i << std::endl;
    };
    call(foo, 1);
    return 0;
}

要编译此程序,我使用的是 GNU C ++编译器 g ++:

To compile this program, I am using the GNU C++ Compiler g++:

$ g++ --version // g++ (Ubuntu 6.5.0-1ubuntu1~16.04) 6.5.0 20181026

C ++ 11 编译后,出现以下错误:

After compiling for C++11, I get the following error:

$ g++ -std=c++11 template_example_1.cpp -Wall

template_example_1.cpp: In function ‘int main(int, const char**)’:
template_example_1.cpp:15:16: error: no matching function for call to ‘call(main(int, const char**)::<lambda(int)>&, int)’
     call(foo, 1);
                ^
template_example_1.cpp:5:6: note: candidate: template<class T> void call(std::function<void(T)>, T)
 void call(std::function<void(T)> f, T v)
      ^~~~
template_example_1.cpp:5:6: note:   template argument deduction/substitution failed:
template_example_1.cpp:15:16: note:   ‘main(int, const char**)::<lambda(int)>’ is not derived from ‘std::function<void(T)>’
     call(foo, 1);
                ^

(与 C ++ 14 C ++ 17

从编译器错误和注释中我了解到,编译器无法推断出lambda的类型,因为它无法与std :: function匹配。

From the compiler error and notes I understand that the compiler failed to deduce the type of the lambda, since it cannot be matched against std::function.

查看先前的问题( 1 2 3 4 ),我对此仍然感到困惑。

Looking at previous questions (1, 2, 3, and 4) regarding this error, I am still confused about it.

如问题3和4的答案所指出,可以通过显式指定模板参数来解决此错误,例如:

As pointed out in answers from questions 3 and 4, this error can be fixed by explicitly specifying the template argument, like so:

int main(int argc, char const *argv[])
{
    ...
    call<int>(foo, 1); // <-- specify template argument type
    // call<double>(foo, 1) // <-- works! Why?
    return 0;
}

但是,当我使用其他类型而不是 int时,例如 double float char bool ,它也可以正常工作,这让我更加困惑。

However, when I use other types instead of int, like double, float, char, or bool, it works as well, which got me more confused.

所以,我的问题如下:


  • 为什么在什么时候起作用我明确指定 int (及其他)作为模板参数?

  • 是否有更通用的解决方法?

  • Why does it work when I explicitly specify int (and others) as the template argument?
  • Is there a more general way to solve this?

推荐答案

A std :: function 不是一个lambda,而lambda不是 std :: function

A std::function is not a lambda, and a lambda is not a std::function.

lambda是具有 operator()和其他一些次要实用程序。您的:

A lambda is an anonymous type with an operator() and some other minor utility. Your:

auto foo = [](int i) {
    std::cout << i << std::endl;
};

struct __anonymous__type__you__cannot__name__ {
  void operator()(int i) { 
    std::cout << i << std::endl;
  }
};
__anonymous__type__you__cannot__name__ foo;

非常粗略(这里有实际的转换为函数的指针以及其他一些我不会介绍的噪音

very roughly (there are actual convert-to-function pointer and some other noise I won't cover).

但是,请注意,它不是 not 继承自 std :: function< void(int)>

But, note that it does not inherit from std::function<void(int)>.

lambda不会推导 std :: function ,因为它们是不相关的类型。模板类型推导是针对传递的参数类型及其基类的精确模式匹配。它不会尝试使用任何形式的转换。

A lambda won't deduce the template parameters of a std::function because they are unrelated types. Template type deduction is exact pattern matching against types of arguments passed and their base classes. It does not attempt to use conversion of any kind.

A std :: function< R (Args ...)> 是一种可以存储任何可复制内容的类型,该可复制内容可以使用与 Args ... 兼容的值来调用并返回与 R 兼容的东西。

A std::function<R(Args...)> is a type that can store anything copyable that can be invoked with values compatible with Args... and returns something compatible with R.

所以 std :: function< void(char)> ; 可以存储可以用 char 调用的任何内容。由于可以使用 char 调用 int 函数,因此可以。

So std::function<void(char)> can store anything that can be invoked with a char. As int functions can be invoked with a char, that works.

尝试一下:

void some_func( int x ) {
  std::cout << x << "\n";
}
int main() {
  some_func('a');
  some_func(3.14);
}

std :: function 将其签名转换为存储在其中的可调用对象。

std::function does that some conversion from its signature to the callable stored within it.

最简单的解决方案是:

template <class F, class T>
void call(F f, T v) {
  f(v);
}

现在,在极少数情况下,您实际上需要签名。您可以在c ++ 17

now, in extremely rare cases, you actually need the signature. You can do this in c++17:

template<class T>
void call(std::function<void(T)> f, T v) {
  f(v);
}
template<class F, class T>
void call(F f_in, T v) {
  std::function f = std::forward<F>(f_in);
  call(std::move(f), std::forward<T>(v));
}






最后,您的 call std :: invoke 的残缺版本 class = post-tag title =显示标记为'c ++ 17'的问题 rel = tag> c ++ 17 。考虑使用它;如果没有,请使用向后移植的版本。


Finally, your call is a crippled version of std::invoke from c++17. Consider using it; if not, use backported versions.

这篇关于无法从lambda函数推断出模板参数std :: function的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆