vendredi 30 octobre 2015

Pass Member Function to Variadic Template Function

I have a class with a function called enqueue:

template<class T, class... Args>
inline auto ThreadPool::enqueue(T && t, Args&&... args) ->std::future<typename std::result_of<T(Args ...)>::type>
{
    using return_type = typename std::result_of<T(Args...)>::type;

    auto task = std::make_shared<std::packaged_task<return_type()>> (
       std::bind(std::forward<T>(t), std::forward<Args>(args)...)
    );

    std::future<return_type> result = task->get_future();
    {
        std::unique_lock<std::mutex> lock(m_mutex);

        // Don't allow job creation after stopping pool.
        if (m_done)
            throw std::runtime_error("Enqueue on stopped ThreadPool.");

        m_tasks.emplace([task]() { (*task)(); });
    }

    m_cond.notify_one();
    m_futures.push_back(move(result));
    return result;
}

This is an inline implementation done inside of the header file alongside the ThreadPool class.

It is a singleton and should be able to take any function with its arguments, add this to a task queue and return a future of the result type of that function.

Here is the class where I am trying to use it:

void Grepper::scan(std::tr2::sys::path const& folder, std::string expression, bool verbose) {
    // Create directory iterators.
    std::tr2::sys::recursive_directory_iterator d(folder);
    std::tr2::sys::recursive_directory_iterator e;

    // Create tasks from files that match initial extension list.
    for (; d != e; ++d) {
        if (!std::tr2::sys::is_directory(d->status()) && std::find(m_extensions.begin(), m_extensions.end(), d->path().extension().generic_string()) != m_extensions.end()) {
            ThreadPool::get_instance().enqueue(grep, d->path(), expression, verbose);
        }
    }
}

Which gives a compiler error of:

Error C3867 'Grepper::grep': non-standard syntax; use '&' to create a pointer to member 

I have tried creating a functor to this function as well as passing the function as a lambda:

ThreadPool::get_instance().enqueue([this](std::tr2::sys::path p, std::string s, bool b) { grep(p, s, b); });

Which gives me the following compiler error:

Error C2893 Failed to specialize function template 'unknown-type std::invoke(_Callable &&,_Types &&...)'

For reference here is the declaration of my grep method:

void grep(std::tr2::sys::path file, std::string expression, bool verbose);

How do I pass this function and its arguments properly to the enqueue method?

Aucun commentaire:

Enregistrer un commentaire