简体   繁体   English

变量模板作为std :: function的参数

[英]Variadic template as parameters to std::function

I want to build a structure that allow me to call member functions with an undefined number of parameters. 我想构建一个允许我用未定义数量的参数调用成员函数的结构。 For now I wrote something like this 现在我写了这样的东西

template<typename Class, typename Return, typename ... Args>
struct Caller
{
private:
    std::function<Return(Args ...)> callerFunction;

    Caller() = delete;
    Caller(const Caller&) = delete;
    Caller(Caller&&) = delete;
    Caller& operator=(const Caller&) = delete;

public:
    ~Caller() = default;

    Caller(Class& instance, Return(Class::*function)(Args ...))
    {
        callerFunction = [&instance, function](Args... args)
        {
            return (instance.*function)(args ...);
        };
    }

    Return operator() (Args ... args)
    {
        return callerFunction(args ...);
    }
};

I am afraid that I cannot work around the fact that I cannot declare a std::function variable as std::function<Return<Args&& ...)> callerFunction 我担心我std::function<Return<Args&& ...)> callerFunction一个事实:我无法将std :: function变量声明为std::function<Return<Args&& ...)> callerFunction

When I try to do this the compiler says that it cannot convert from int to int&& (if for example the parameters are int s), so I'm guessing that the function sees the Args&& ... as a parameter pack of rvalue references. 当我尝试这样做时,编译器说它不能从int转换为int&& (例如,如果参数是int ),所以我猜测该函数将Args&& ...视为rvalue引用的参数包。 Am I correct? 我对么?

Is there a workaround? 有解决方法吗?

Edit: Ok, I was declaring the function inside the Caller constructor in the wrong way. 编辑:好的,我以错误的方式在Caller构造函数中声明了该函数。

Wrong way --> Caller(Class& instance, Return(Class::*function)(Args&& ...)) 错误的方式 - > Caller(Class& instance, Return(Class::*function)(Args&& ...))

Right way --> Caller(Class& instance, Return(Class::*function)(Args ...)) 正确的方法 - > Caller(Class& instance, Return(Class::*function)(Args ...))

The (I guess) right implementation is (我猜)正确的实现是

template<typename Class, typename Return, typename ... Args>
struct Caller
{
private:
    std::function<Return(Args&& ...)> callerFunction;

    Caller() = delete;
    Caller(const Caller&) = delete;
    Caller(Caller&&) = delete;
    Caller& operator=(const Caller&) = delete;

public:
    ~Caller() = default;

    Caller(Class& instance, Return(Class::*function)(Args ...))
    {
        callerFunction = [&instance, function] (Args&&... args)
        {
            return (instance.*function)(std::forward<Args>(args) ...);
        };
    }

    Return operator() (Args&& ... args)
    {
        return callerFunction(std::forward<Args>(args) ...);
    }
};

Now the question is: Why do I need to declare the function anyway without the double &? 现在的问题是:为什么我需要在没有double&?的情况下声明函数?

When you define your class template like this: 当您像这样定义类模板时:

template <typename T>
struct A {
 A(T&& param)
}

And then create an instace: 然后创建一个实例:

A<int> myInstance(someIntVariable);

It won't compile . 它不会编译 The reason is, the type of T is explicitly specified by you (as an int , in A<int> ), and your class constructor parameter is no longer T&& , but int&& , so it's no longer universal reference (which accepts both lvalue and rvalue references), but regular rvalue reference. 原因是, T的类型由您明确指定(作为int ,在A<int> ),并且您的类构造函数参数不再是T&& ,而是int&& ,因此它不再是通用引用(它同时接受左值和右值参考),但是常规右值参考。

Next, if you pass it some integer, there is a type missmatch error because you pass a regular variable when rvalue reference is expected. 接下来,如果传递一些整数,则会出现类型不匹配错误,因为在期望rvalue引用时传递常规变量。

In your example you explicitly defined function signatures, so the same applies - constructor expects a function taking rvalue references to Args..., but that's not true. 在您的示例中,您明确定义了函数签名,因此同样适用 - 构造函数需要一个函数将rvalue引用到Args ...,但事实并非如此。

I think it's better explained in this question 我认为在这个问题中解释得更好

int&& is not the same as int . int&&int If your method takes an int , it doesn't take an int&& . 如果您的方法采用int ,则不需要int&& They are different types. 它们是不同的类型。

There is no conversion between different signatures of member function pointer. 成员函数指针的不同签名之间没有转换。

Forwarding references aren't magic. 转发引用并不神奇。 They depend on deduction rules (and no use of Args&&... above is in a deduced context) and on reference collapsing rules. 它们依赖于演绎规则(并且不使用上面的Args&&...在推导的上下文中)和参考折叠规则。

As such, your 就这样,你的

Return operator() (Args&& ... args)

is also wrong. 也是错的。 If Args... is int , then you won't be able to call the above with int a; blah.operator()(a) 如果Args...int ,那么你将无法使用int a; blah.operator()(a)调用上面int a; blah.operator()(a) int a; blah.operator()(a) as a won't bind to int&& . int a; blah.operator()(a)作为a不会绑定到int&&

Honestly, your entire type should be thrown out and replaced with a std::function<Return(Args...)> . 老实说,你的整个类型应该被抛出并替换为std::function<Return(Args...)> Class is a useless narrowing of what the function does, and your wrappers don't add much either. Class是函数所做的无用的缩小,你的包装器也不会增加太多。

Users can just [&a](auto&&...args)->decltype(auto){ return a.foo(decltype(args)(args)...); } 用户只需[&a](auto&&...args)->decltype(auto){ return a.foo(decltype(args)(args)...); } [&a](auto&&...args)->decltype(auto){ return a.foo(decltype(args)(args)...); } if they really need to replicate your constructor, or use std::bind( &A::foo, std::ref(a) ) [&a](auto&&...args)->decltype(auto){ return a.foo(decltype(args)(args)...); }如果他们真的需要复制你的构造函数,或使用std::bind( &A::foo, std::ref(a) )

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

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