传递成员函数到变量模板函数。

问题描述 投票:2回答:1

我有一个类,它有一个叫做enqueue的函数,这是一个在头文件里面和ThreadPool类一起做的内联实现。

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;
}

这是一个在头文件中的内联实现, 和ThreadPool类一起。

它是一个单例,应该能够接受任何带有参数的函数,将其添加到任务队列中,并返回该函数的结果类型的未来。

这是我试图使用它的类。

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);
        }
    }
}

它给出的编译器错误是:

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

我试着为这个函数创建了一个漏斗函数 也试着把函数作为lambda传入

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

结果出现了如下的编译器错误

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

这里是我的grep方法的声明,供参考。

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

我如何将这个函数和它的参数正确地传递给enqueue方法?

c++ c++11 templates variadic-templates
1个回答
2
投票

使用指向成员函数的指针的尝试失败了,原因有两个。

  1. 要形成一个指向成员函数的指针,你需要使用... ... &Grepper::grep 语法。
  2. 一个成员函数需要一个隐式的对象参数(在其他参数中,所以它也可以由 std::bindstd::result_of).

说了这么多,你可以试试下面的调用。

ThreadPool::get_instance().enqueue(
   &Grepper::grep
   , this
   , d->path()
   , expression
   , verbose
);

用lambda表达式进行的尝试失败了 因为那个lambda表达式作为参数传递给了你。

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

声明了三个参数,所以 Args 参数包不能为空。但是 在你的情况下,这些参数。

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

这些参数,根据你的设计,应该在调用中传递给 enqueue:

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

或由lambda表达式捕获,因此不需要额外的 Args 需要。

ThreadPool::get_instance().enqueue(
    [this,d,expression,verbose] { grep(d->path(), expression, verbose); }
);
© www.soinside.com 2019 - 2024. All rights reserved.