title: Expanding on a Job/Worker multi-threading system in C++
body: <p>I've been reading a tutorial by Ben Hoffman (<a href="https://benhoffman.tech/cpp/general/2018/11/13/cpp-job-system.html" rel="nofollow noreferrer">https://benhoffman.tech/cpp/general/2018/11/13/cpp-job-system.html</a>)</p>
  
  <p>I've had a go at bashing together a version of the Job/Worker system he has, but instead of using <code>void*</code> for arguments then casting to a known struct, I've been trying to use variadic arguments. The idea is, a job takes in a "parent" to perform a method on, the function pointer to said method, and an <code>Args...</code> for the argument(s). However, I get an internal compiler error if I try to build. Here is the job class:</p>
  
  <pre><code>template &lt;class T, typename... Args&gt;
  struct JobMemberFunc : IJob
  {
      JobMemberFunc(T* aParent, void (T::* f)(Args...), Args... Args)
      {
          parentObj = aParent;
          func_ptr = f;
          saved_args = ::std::make_tuple (::std::move(Args)...);
      }
  
      virtual bool invoke() override
      {
          if (!parentObj) { return false; }
  
          (parentObj-&gt;*func_ptr)(::std::move(saved_args));
          return true;
      }
  
      /** the object to invoke the function pointer on */
      T* parentObj;
  
      /** The function pointer to call when we invoke this function */
      void (T::* func_ptr)(Args...);
  
      ::std::tuple&lt;Args...&gt; saved_args;
  };
  
  
  struct CpuJob
  {
      IJob* jobPtr = nullptr;
  };
  </code></pre>
  
  <p>Then there's the AddJob method, where the internal compiler error is actually happening.</p>
  
  <pre><code>template &lt;typename T, typename... Args&gt;
  void AddJob(T* aParent, void(T::* func_ptr)(Args...), Args... args)
  {//This curly bracket is where the internal compiler error happens
      CpuJob aJob = {};
  
      JobMemberFunc&lt;T, Args...&gt;* jobPtr = new JobMemberFunc&lt;T, Args...&gt;(aParent, func_ptr, 
      std::forward&lt;Args&gt;(args)...);
  
      aJob.jobPtr = jobPtr;
  
      locklessReadyQueue.enqueue(aJob);
  }
  </code></pre>
  
  <p>More than happy to be told this is a bad/wrong way of trying to do it anyway. I have thought about doing away with it and having a standardized argument list or doing something polymorphic but I really wanna make this work so I can literally ask the job system to do anything I like.</p>
  
  <p>Thanks!</p>