首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何创建接受引用而不是副本的可变模板方法?

如何创建接受引用而不是副本的可变模板方法?
EN

Stack Overflow用户
提问于 2020-07-31 15:49:46
回答 1查看 29关注 0票数 1

我们有一个模板方法,它使用线程池,根据可用的系统线程数,一般并行地执行某些成员函数。

该方法必须使用的两个参数是固定的,第一个是线程索引,第二个是线程数。

这样,这些方法就可以执行如下操作:

代码语言:javascript
复制
for(i = threadIndex; i < workContainer.size(); i += numThreads) 
{
  // So this thread will only do every numThreads piece of the work from the workContainer, with no overlap between threads
}

这是一个很好的方法,下面是这个方法的样子:

代码语言:javascript
复制
  template <class S, class Args>
  void parallelWork(S* self, void (S::*workfcn)(const unsigned, const unsigned, Args*), Args* args)
  {
    auto work = [&](const unsigned threadIndex, const unsigned nthreads, S* self, Args* args)

    {
      std::string* rc = nullptr;

      try
        {
          (self->*workfcn)(threadIndex, nthreads, args);
        }
      catch (std::exception& err)
        {
          rc = new std::string(err.what());
        }

      return rc;
    };

    ulong nthreads = size();
    std::vector<std::string*> rc(nthreads);

    if (1 == nthreads)
      {
        rc[0] = work(0, 1, self, args);
      }
    else
      {
        std::vector<std::future<std::string*>> frc(nthreads);

        for (unsigned i = 0; nthreads > i; ++i)
          frc[i] = enqueue(work, i, nthreads, self, args);

        // Wait for all
        for (unsigned i = 0; nthreads > i; ++i)
          rc[i] = frc[i].get();
      }

    for (unsigned i = 0; nthreads > i; ++i)
      {
        if (rc[i])
          {
            HELAS_ERROR(std::string("Thread ") + std::to_string(i) + ": " + *rc[i]); delete rc[i];
          }
      }
  }

然而,这是有限的。当前解决方案要求我们有效地将所有参数(其中一些是引用)放入结构中,然后将指向该结构的指针传递到此parallelWork()方法。

如果我们可以直接传递方法应该采用的参数,那不是很好吗?IE,不是这样做的:

代码语言:javascript
复制
struct ThreadArgs 
{
  const std::vector<int>& inArg1;
  double inArg2;
  SomeClass* inarg3;
  std::vector<std::vector<double>> outArg1; // outer vector is per-thread
}
代码语言:javascript
复制
void MyClass::doFooInParallel() 
{
  std::vector<int> inArg1;
  double inArg2;
  SomeClass* cp = getSomeClass();
  std::vector<std::vector<double>> outArg1(numThreads);

  ThreadArgs args = ThreadArgs(inArg1, inArg2, cp, outArg1);

  parallelWork(this, &MyClass::foo, &args);
}

我们可以这样做:

代码语言:javascript
复制
void MyClass::doFooInParallel() 
{
  std::vector<int> inArg1;
  double inArg2;
  SomeClass* cp = getSomeClass();
  std::vector<std::vector<double>> outArg1(numThreads);

  parallelWork(this, &MyClass::foo, inArg1, inArg2, cp, outArg1);
}

它似乎是一个不同的模板将是解决方案,将方法的开始改为:

代码语言:javascript
复制
  template <class S, class... Args>
  void parallelWork(S* self,void (S::*workfcn)(const unsigned, const unsigned, Args... args),Args... args)
  {
    auto work = [&](const unsigned threadIndex, const unsigned nthreads,S* self, Args... args)

这确实与我们当前使用的方法进行了编译。然而,存在一个问题--这些论点是按值传递的,而不是按引用传递的.

对于输入,这可能并不坏,有些可能通过复制省略而消除。但是,对于传递的变量,即方法的输出(就像向量n线程大小与每个线程的输出一样),这显然是不起作用的--它意味着并行地执行工作,而实际上什么也不做。

我试过像这样引用他们:

代码语言:javascript
复制
  template <class S, class... Args>
  void parallelWork(S* self,void (S::*workfcn)(const unsigned, const unsigned, Args&&... args),Args&&... args)
  {
    auto work = [&](const unsigned threadIndex, const unsigned nthreads,S* self, Args&&... args)

然而,当我们尝试使用它时,这是失败的。

could not match type-parameter 0-1&& against (the actual parameter we tried to pass)

(单次引用也失败,但我测试了以防万一)

解决这一问题的办法是什么?这在C++11中是可能的,还是只适用于后来C++标准中的特性?

std::forwardstd::refstd::cref在这里会有所帮助吗?

这实际上是一个概念性的问题,所以请原谅我,所有这些代码都不能运行,要想得到所有这些的可运行的示例,这将是一项巨大的工作,我认为这个问题已经得到了很好的解释,足以涵盖它,但是如果需要澄清,请告诉我。

EN

回答 1

Stack Overflow用户

发布于 2020-07-31 16:06:09

&&不是引用,而是r值(可以是引用,也可以是值)。您应该使用Args& ...。我认为问题在于您使用的是template <class S, class... Args>,您应该在其中使用template <class S, typename... Args>,因为您的参数似乎并不总是类。

如果您想使用转发(例如,std::vector.emplace_back ),可以使用Args && ...,然后对函数使用std::forward参数。在您的例子中,您应该注意到,使用std::forward仍然会通过值而不是引用传递您的参数。要实现通过r值传递参数,请使用std::move

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63195090

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档