C++模板函数从可调用类实例到std::function

huangapple go评论118阅读模式
英文:

C++ template function from callable class instance to std::function

问题

I do need std::function for stateful operation.

So I would like to make an instance of a class implementing operator() into std::function. I did test std::bind works, but can't wrap it up as a function.

  1. struct StatefulOperation
  2. {
  3. StatefulOperation(int num) : num_(num) {}
  4. int operator()(int i)
  5. {
  6. num_ += i;
  7. return num_;
  8. }
  9. int num_;
  10. };
  11. // This works
  12. const StatefulOperation obj(40);
  13. using std::placeholders::_1;
  14. std::function<int(int)> op = std::bind(&StatefulOperation::operator(), obj, _1);
  15. // Want something like this
  16. template<typename A, typename B, typename C>
  17. std::function<B(A)> op(C& obj);
  18. // This doesn't work
  19. template<typename A, typename B, typename C>
  20. std::function<B(A)> op(C& obj)
  21. {
  22. using std::placeholders::_1;
  23. return std::bind(&C::operator(), obj, _1);
  24. }

The last implementation attempt fails with an error like below:

  1. main.cpp:52:21: note: template argument deduction/substitution failed:
  2. main.cpp:75:35: note: couldn't deduce template parameter 'A'
  3. 75 | std::function<int(int)> f = op(a);
  4. | ~~^~~

How can I get this done?

英文:

I do need std::function for stateful operation.

So I would like to make an instance of a class implementing operator() into std::function. I did test std::bind works, but can't wrap it up as a function.

  1. struct StatefulOperation
  2. {
  3. StatefulOperation(int num) : num_(num) {}
  4. int operator()(int i)
  5. {
  6. num_ += i;
  7. return num_;
  8. }
  9. int num_;
  10. };
  11. // This works
  12. const StatefulOperation obj(40);
  13. using std::placeholders::_1;
  14. std::function&lt;int(int)&gt; op = std::bind(&amp;StatefulOperation::operator(), obj, _1);
  15. // Want something like this
  16. template&lt;typename A, typename B, typename C&gt;
  17. std::function&lt;B(A)&gt; op(C&amp; obj);
  18. // This doesn&#39;t work
  19. template&lt;typename A, typename B, typename C&gt;
  20. std::function&lt;B(A)&gt; op(C&amp; obj)
  21. {
  22. using std::placeholders::_1;
  23. return std::bind(&amp;C::operator(), obj, _1);
  24. }

The last implementation attempt fails with error like below;

  1. main.cpp:52:21: note: template argument deduction/substitution failed:
  2. main.cpp:75:35: note: couldnt deduce template parameter A
  3. 75 | std::function&lt;int(int)&gt; f = op(a);
  4. | ~~^~~

How can I get this done?

答案1

得分: 2

编译器无法仅从返回类型中推断出AB,您需要指定它们:

  1. std::function<int(int)> f = op<int, int>(a);

然而,您实际上不需要这些额外的模板参数。只需使用auto来推断返回类型:

  1. template<typename C>
  2. auto op(C& obj)
  3. {
  4. using std::placeholders::_1;
  5. return std::bind(&C::operator(), std::ref(obj), _1);
  6. }

返回类型不会完全相同,但可以转换为您想要的std::function<B(A)>。如果您想指定确切的返回类型,可以结合使用thisstd::invoke_result_t来实现。

英文:

The compiler cannot deduce A and B just from the return type. You need to specify them:

  1. std::function&lt;int(int)&gt; f = op&lt;int, int&gt;(a);

However, you don't really need these additional template parameters. Just use auto to deduce the return type:

  1. template&lt;typename C&gt;
  2. auto op(C&amp; obj)
  3. {
  4. using std::placeholders::_1;
  5. return std::bind(&amp;C::operator(), std::ref(obj), _1);
  6. }

The return type will not be exactly the same, but convertible to what you want (std::function&lt;B(A)&gt;). If you want to specify the exact return type, you can do so with a combination of this and std::invoke_result_t.

答案2

得分: 1

Instead of using bind you should use lambda expressions. Also you StatefulOperation should NOT be const (otherwise it can't update its internal state).

  1. #include <functional>
  2. #include <iostream>
  3. struct StatefulOperation
  4. {
  5. StatefulOperation(int num) : num_(num) {}
  6. int operator()(int i)
  7. {
  8. num_ += i;
  9. return num_;
  10. }
  11. int num_;
  12. };
  13. int main()
  14. {
  15. /*const*/ StatefulOperation obj(40); // your state cannot be const since you are changing its internal state
  16. // instead of bind rely on lambda expressions (bind is still there because of well... history)
  17. std::function<int(int)> op{ [&](int num) { return obj(num); } };
  18. for (int i = 0; i < 10; ++i)
  19. {
  20. std::cout << op(i) << " ";
  21. }
  22. return 0;
  23. }
英文:

Instead of using bind you should use lambda expressions. Also you StatefulOperation should NOT be const (otherwise it can't update its internal state).

  1. #include &lt;functional&gt;
  2. #include &lt;iostream&gt;
  3. struct StatefulOperation
  4. {
  5. StatefulOperation(int num) : num_(num) {}
  6. int operator()(int i)
  7. {
  8. num_ += i;
  9. return num_;
  10. }
  11. int num_;
  12. };
  13. int main()
  14. {
  15. /*const*/ StatefulOperation obj(40); // your state cannot be const since you are changing its internal state
  16. // instead of bind rely on lambda expressions (bind is still there because of well... history)
  17. std::function&lt;int(int)&gt; op{ [&amp;](int num) { return obj(num); } };
  18. for (int i = 0; i &lt; 10; ++i)
  19. {
  20. std::cout &lt;&lt; op(i) &lt;&lt; &quot; &quot;;
  21. }
  22. return 0;
  23. }

答案3

得分: 0

你可以用最简单的方式初始化一个std::function,因为你的类是可调用的,实现了一个具有期望类型的函数调用运算符:

  1. std::function<int(int)> op{StatefulOperation(40)};

不要忘记,当复制op时,状态也会被复制。

英文:

Since your class is a callable that implements a function call operator with the expected types, you can initialize a std::function in the most simple way:

  1. std::function&lt;int(int)&gt; op{StatefulOperation(40)};

Do not forget that the state is copied when op is copied.

huangapple
  • 本文由 发表于 2023年7月4日 20:43:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/76612778.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定