简体   繁体   English

类型推断不适用于std :: function

[英]Type deduction does not work with std::function

I have the following problem. 我有以下问题。 When I try to compile the following code 当我尝试编译以下代码时

template< typename T >
T func( T t)
{
  return t;
}

template< size_t N, typename T >
void foo( std::function< T(T) > func )
{
  // ...
}

int main()
{
  foo<3>( func<float> );

  return 0;
}

I get the error: 我得到错误:

 no matching function for call to 'foo'
      foo<3>( func<float> );
      ^~~~~~
/Users/arirasch/WWU/dev/xcode/tests/tests/main.cpp:18:10: note: candidate template ignored: could not match 'function<type-parameter-0-1 (type-parameter-0-1)>' against 'float (*)(float)'
    void foo( std::function< T(T) > func )

However, when I fix it to 但是,当我修复它

template< typename T >
T func( T t)
{
  return t;
}

template< size_t N, typename T >
void foo( std::function< T(T) > func )
{
  // ...
}

int main()
{

  std::function< float(float) > input_func = func<float>;
  foo<3>( input_func );

  return 0;
}

ie, when I declare the input function of foo explicitly as std::function< float(float) > , the compilation can be done successfully. 即,当我将foo的输入函数显式声明为std::function< float(float) > ,编译可以成功完成。

Does anyone know how I can fixe my code alternatively so that I can simply write something like foo<3>( func<float> ); 有谁知道我可以如何修正我的代码,以便我可以简单地编写诸如foo<3>( func<float> ); (according to my first code example) instead of (根据我的第一个代码示例),而不是

std::function< float(float) > input_func = func<float>;
foo<3>( input_func );

where the type of input_func must be explicitly stated? 在哪里必须明确声明input_func的类型?

Many thanks in advance. 提前谢谢了。

The problem here is that the compiler must do overload resolution to find out which std::function<U(U)> instantiations have constructor(s) that can take a T(*)(T) . 这里的问题是,编译器必须执行重载解析才能找出哪些std::function<U(U)>实例化具有可以采用T(*)(T)构造函数。 That is to say, there might be multiple types each of which may have multiple ctors that could take your input_func . 就是说,可能有多种类型,每种类型可能都有多个input_func ,它们可能占用您的input_func

Now, if you look at the Standard, you'll find that there is no such overload specified for std::function , but the overload resolution rules are the same for all templates, whether they're from std:: , boost:: or ACME:: . 现在,如果看一下Standard,您会发现没有为std::function指定这样的重载,但是所有模板的重载解决规则都是相同的,无论它们来自std::boost::ACME:: The compiler won't start instantiating templates to find a conversion sequence. 编译器不会开始实例化模板以查找转换序列。

Once you provide a perfect match, there's no need for a conversion sequence. 提供完美匹配后,就无需转换顺序了。 There's exactly one target type for which no conversion sequence is needed, and the compiler deduces this type. 恰好只有一种目标类型不需要转换序列,编译器会推断出这种类型。

In this particular case, you know about the relation between function pointers and std::function , and also about the specific restriction that you must have a unitary function which returns the same type (no T(*)(U) ) so you could add an overload 在这种特殊情况下,您将了解函数指针与std::function之间的关系,以及特定的限制,即您必须具有一个返回相同类型(没有T(*)(U) )的单一函数,因此您可以增加过载

template< size_t N, typename T >
void foo(T(*func)(T))
{
  return foo<N>(std::function<T(T)>(func));
}

Type deduction does not work in your case simply because it cannot be deduced. 类型推论在您的情况下不能正常工作,因为不能推导它。 Type deduction is, in most cases, a simple match with types and other template parameters. 在大多数情况下,类型推导是与类型和其他模板参数的简单匹配。 There is however some dark corner of C++ that deal with deduction that has some funky rules, but I won't go into it for this answer. 但是,C ++的某些暗角处理一些时髦的规则,但是我不会在此回答。

This is an example where the compiler can deduce template arguments: 这是编译器可以推断模板参数的示例:

template<typename T>
void test(std::vector<T>);

test(std::vector<int>{1, 2, 3, 4, 5, 6});

This is easy for the compiler. 这对于编译器来说很容易。 It need a std::vector of T . 它需要Tstd::vector You give it a std::vector of int . 您给它一个std::vector int T must be int . T必须是int

However, in your case, There is a lot more stuff happening: 但是,在您的情况下,发生了很多事情:

template<typename T>
void test(std::function<T(T)>);

int someFunc(int);

test(someFunc);

The compiler can't do the match. 编译器无法进行匹配。 Try for yourself: Give me a T that will make those two types equal: int(*)(int) to std::function<T(T)> . 自己尝试:给我一个T ,它将使这两种类型相等: int(*)(int)std::function<T(T)> Indeed, there is no possible T that can make those two type to be the same, whereas the vector version was an easy match. 事实上,有没有可能T ,可以使这两个类型是相同的,而矢量版本是一个容易的比赛。

You will say to me: "but... a pointer to a function is convertible to a std::function you silly!" 您会对我说:“但是……指向函数的指针可以转换为std :: function,这很愚蠢!” Yeah, it is convertible, indeed. 是的,确实可以兑换。 But before any conversion, the compiler has to find what T is. 但是在进行任何转换之前,编译器必须找到T是什么。 Without T , you make the conversion from a pointer to function to what class? 如果没有T ,则将指针从函数转换为什么类? Many class? 很多班? Try to match every T ? 尝试匹配每个T吗? There is multiple possibility where your function would be convertible. 您的函数可以转换的可能性有多种。


How can you make this work? 你如何使这项工作? Forget the std::function . 忘记std::function Just receive T . 刚收到T

template<typename T>
T func(T t) {
  return t;
}

template<size_t N, typename T>
void foo(T func) {
  // ...
}

int main()
{
  foo<3>( func<float> );

  return 0;
}

Notice how this example works well. 注意此示例的工作方式。 You have no conversion, no std::function thingy and can work with any callable you can possibly imagine! 您没有转换,没有std::function麻烦,并且可以与您可以想象的任何可调用对象一起使用!

Are you worried about accepting any type? 您是否担心接受任何类型? No worry here! 不用担心! Parameter types are a bad way to express what a template can do with received parameters anyway. 参数类型是表达模板对接收到的参数仍然可以执行的操作的一种不好方法。 You should restrict it with an expression . 您应该使用表达式来限制它。 That expression will tell others how you will use T and what interface T need to have. 该表达式将告诉其他人您将如何使用T以及T需要具有什么接口。 btw, we call that sfinae: 顺便说一句,我们称这个sfinae:

template<size_t N, typename T>
auto foo(T func) -> decltype(void(func(std::declval<int>()))) {
  // ...
}

In this example, you restrict func to be callable with a int and still return void . 在此示例中,将func限制为可以使用int调用的func ,并且仍然返回void

Casting func to an std::function explicitly solves the problem. 将func强制转换为std :: function可明确解决该问题。 Eg the code below works. 例如,下面的代码有效。

template< typename T >
T func( T t)
{
  return t;
}

template<typename T>
using FuncType = std::function<T(T)>;

template< size_t N, typename T >
void foo( FuncType<T> func )
{
  // ...
}

int main()
{
  func<float>(1.0);
  foo<3>( FuncType<float>(func<float>) );

  return 0;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM