简体   繁体   English

如何在 c++17 中传递一个 Callable 对象以与 std::invoke 一起使用

[英]How to pass a Callable object in c++17 to be used with std::invoke

Why the following does not compile when passing i to the constructor.为什么以下在将i传递给构造函数时无法编译。 The other similar constructs compile.其他类似的结构编译。

#include <iostream>
#include <functional>

int RetXPrintU(int x, uint u)
{
    std::cout << "RetXprintU(): " << u << std::endl;
    return x;
}

template <typename Fn, typename... Args>
void Call(Fn&& fun, Args&&... args)
{
    std::invoke(std::forward<Fn>(fun), std::forward<Args>(args)...);
}

template <typename Fn, typename... Args>
class CallableObj
{
public:
    explicit CallableObj(Fn&& fun, Args&&... args)
    {
        std::invoke(std::forward<Fn>(fun), std::forward<Args>(args)...);
    }
};

int main() {
    int i = 4;
    std::invoke(RetXPrintU, i, 8u);
    Call(RetXPrintU, i, 8u);
    CallableObj co(RetXPrintU, i, 8u); // WHY I DO NOT COMPILE?
    //CallableObj co(RetXPrintU, 0, 8u); // WHY I COMPILE?

    return 0;
}

The issue here is you need to move the template from the class to the constructor.这里的问题是您需要将模板从类移动到构造函数。 When you have当你有

template <typename Fn, typename... Args>
class CallableObj
{
public:
    explicit CallableObj(Fn&& fun, Args&&... args)
    {
        std::invoke(std::forward<Fn>(fun), std::forward<Args>(args)...);
    }
};

Args&&... is not a variadic forwarding reference because it is deduced for the class itself and when you call CallableObj co(RetXPrintU, i, 8u); Args&&...不是可变参数转发引用,因为它是为类本身以及当您调用CallableObj co(RetXPrintU, i, 8u);推导出来的CallableObj co(RetXPrintU, i, 8u); the class is instantiated and the constructor gets stamped out as该类被实例化,构造函数被标记为

explicit CallableObj(int(int, unsigned int)&& fun, int&& arg1, unsigned int&& arg2)

What we want is我们想要的是

class CallableObj
{
public:
    template <typename Fn, typename... Args>
    explicit CallableObj(Fn&& fun, Args&&... args)
    {
        std::invoke(std::forward<Fn>(fun), std::forward<Args>(args)...);
    }
};

so that now Args will be deduced when the constructor is called and Args&& is now a forwarding reference.这样现在在调用构造函数时Args导出Args&&并且Args&&现在是转发引用。

The reason CallableObj co(RetXPrintU, 0, 8u);原因CallableObj co(RetXPrintU, 0, 8u); worked in your example is because 0 is a prvalue and a prvalue can bind to an rvalue reference.在你的例子中工作是因为0是一个纯右值,一个纯右值可以绑定到一个右值引用。

As the error message says, the compiler can't deduce the template parameters for CallableObj .正如错误消息所说,编译器无法推导出CallableObj的模板参数。 You need add a deduction guide for that:您需要为此添加一个扣除指南:

template <typename Fn, typename... Args>
CallableObj(Fn&& fun, Args&&... args) -> CallableObj<Fn, Args>...>;

The whole code reads:整个代码如下:

template <typename Fn, typename... Args>
class CallableObj
{
public:
    explicit CallableObj(Fn fun, Args... args)
    {
        std::invoke(std::forward<Fn>(fun), std::forward<Args>(args)...);
    }
};

template <typename Fn, typename... Args>
CallableObj(Fn&& fun, Args&&... args) -> CallableObj<Fn, Args...>;

As @Jarod42 pointed out there's no need to make the constructor a template itself (as it was in the first version of the answer).正如@Jarod42 指出的那样,没有必要让构造函数本身成为模板(就像在答案的第一个版本中一样)。

And here is a live example (corrected version by @Jarod42).这是一个实时示例(@ Jarod42 的更正版本)。

I was assuming your code is just a minimal example and you need the class to be a template.我假设你的代码只是一个最小的例子,你需要这个类作为模板。 If that is not the case you better go with the other solution.如果不是这种情况,您最好采用其他解决方案。

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

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