C ++ 11 std :: forward一个指针 [英] C++11 std::forward a pointer

查看:141
本文介绍了C ++ 11 std :: forward一个指针的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在应用程序中有一个信号类,为类提供了暴露事件的选项(与.NET中相同)。

I have a Signal class in my application that provides classes with an option to expose events (same as in .NET).

这个班的工作和一切都很好。

The class works and all is well.

昨天我看到这个SO问题(及其答案),并熟悉 std :: forward

Yesterday I saw this SO question (and its answer) and was familiarized with std::forward.

我决定尝试在我的代码中使用它,所以我改变每个 std :: function< void(Args ...)> std :: function< void(Args& ...)> 运算符())我使用了上面链接中看到的相同的逻辑,所以现在函数 Args& ... args 回调使用 std :: forward< Args>(args)...

I decided to try to use it in my code so I changed every std::function<void(Args...)> to std::function<void(Args&&...)> and in the raise function (the operator()) I used the same logic I saw in the above link so now the function takes Args&&...args and the callback uses std::forward<Args>(args)...

类(有一些更改,使它成为一个很好的例子):

Here's a simplified version of my Signal class (with some changes to make it a good example):

template<typename... Args> class Signal
{
public:
    int operator+=(const std::function<void(Args&&...)>& func)  {
        int token = getNewToken();
        m_subscribers.emplace(token, func);
        return token;
    }

    void operator()(Args&&... args) {
        for (auto it : m_subscribers) {
            it.second(std::forward<Args>(args)...);
        }
    }

private:
    std::map<int, std::function<void(Args&&...)>> m_subscribers;
};

int main() {
    int* six = new int(6);
    int seven = 7;

    Signal<int*> e1;
    e1 += [](int* x) { std::cout << *x; };

    Signal<int> e2;
    e2 += [](int x) { std::cout << x; };

    e1(&seven);
    e2(6);

    e1(six);  //Error C2664 'void Signal<int *>::operator ()(int *&&)': 
              //  cannot convert argument 1 from 'int *' to 'int *&&'
    e1(std::move(six)); //This is a workaround          
    return 0;
}

我看到的问题是类(或 main 在这个例子中)尝试用指针引发事件,我不知道如何解决这个。

The issue I'm seeing is with classes (or main in this example) that try to raise events with pointers and I'm not sure how to solve this.

我的主要目标是如果开发人员选择使用 Signal ,我不希望他使用 std :: move

My main goal is to have the Signal class a general API and if the developers chose to use Signal<int*> I don't want him\her to raise with std::move.

我在这里做错了什么?

推荐答案

T&&& 非cv限定函数模板参数。在您的调用操作符中:

T&& is only a universal reference if T is a non-cv-qualified function template parameter. In your call operator:

void operator()(Args&&... args) {

Args 不是函数的模板参数,它是一个模板参数的类。因此对于 Signal ,此运算符() int * 。因为 six 是一个左值,所以失败。

Args isn't a template parameter of the function, it's a template parameter of the class. So for Signal<int*>, this operator() takes an rvalue reference to int*. Since six is an lvalue, that fails.

你想要的是提供正确的参考资格到信号。像这样:

What you want is to provide the correct reference qualifications to Signal. Like so:

template<typename... Args>
class Signal
{
    using F = std::function<void(Args...)>; // NB: Just Args...
public:
    int operator+=(F func)  {
        int token = getNewToken();
        m_subscribers.emplace(token, std::move(func));
        return token;
    }

    void operator()(Args... args) {       // NB: just Args...
        for (auto& it : m_subscribers) {  // NB: auto&
            it.second(args...);
        }
    }

private:
    std::map<int, F> m_subscribers;
};

请注意,转发 Args ... 可疑。如果你有两个订阅者怎么办?一旦你转发参数,一旦你不能真正使用他们第二次。

Note that forwarding Args... is questionable anyway. What if you had two subscribers? Once you forward the args once you can't really use them a second time.

以上将使信号< int *> 运算符()只需要一个 int * ,你可以传递一个左值或右值。

The above will make Signal<int*> do what you expect. The operator() will just take an int*, which you can pass either an lvalue or an rvalue to.

这篇关于C ++ 11 std :: forward一个指针的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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