8

考虑下面的代码:

#include <memory>
#include <future>

using namespace std;

template <typename T, typename Work>
void Test2(future<T> f, Work w)
{
  async([](future<T> && f, Work w)
                      {}, move(f), move(w));
}

int main()
{
  future<int> x = std::async([]()->int{
        std::this_thread::sleep_for(std::chrono::microseconds(200));
        return 10;
    });

  Test2(std::move(x), [](int x){});
    return 0;
}

上述失败并出现以下编译器错误:

错误 1 ​​错误 C2664: 'void Test2::::operator ()(std::future<_Ty> &&,Work) const' : 无法将参数 1 从 'std::future<_Ty>' 转换为 'std::future <_Ty> &&' c:\program files (x86)\microsoft visual studio 11.0\vc\include\xrefwrap 98 1 ConsoleApplication6

GCC 4.7.2 编译得很好 http://ideone.com/KhMiV6

在我继续在 Microsoft Connect 上报告之前:

1)这是VC11的一个错误还是这实际上是标准行为?

2)有没有人知道这个的解决方法?

编辑:我已经在Microsoft Connect上报告了它。为了更快地解决问题,我们鼓励您对其进行投票。

4

1 回答 1

5

嗯,这似乎是VC11中的一个错误。显然,实现async并没有真正转发参数,而是复制它们。

从头顶开始,我将为右值创建一个小包装器,在复制包装器时移动构造元素:

    template <typename T>
    struct rvref_wrapper {
        rvref_wrapper(T&& value) : value_(std::move(value)) {}
        rvref_wrapper(rvref_wrapper const& other) : value_ (other.get()) {}
        T&& get() const { return std::move(value_); }
        mutable T value_;
    };

    template <typename T>
    auto rvref(T&& x) -> rvref_wrapper<typename decay<T>::type> {
       return std::move(x);
    }

然后您必须修改您的测试场景,以便 lambda inTest2采用包装器而不是future自身:

    template <typename T, typename Work>
    void Test2(future<T> f, Work w)
    {
      async([](rvref_wrapper<future<T>> fr, Work w) {
          // acquire future<T>&& here
          future<T> f(fr.get());
          // e.g. call work with future value
          w(f.get());
      }, rvref(f), move(w));
    }

    int main()
    {
        future<int> x = std::async([]()->int{
            std::this_thread::sleep_for(std::chrono::microseconds(200));
            return 10;
        });

        Test2(std::move(x), [](int x){});
        return 0;
    }

看起来有点难看,但至少它可以编译。希望对你有帮助!

于 2013-04-22T09:22:57.517 回答