将成员函数传递给可变参数模板函数 [英] Pass Member Function to Variadic Template Function

查看:123
本文介绍了将成员函数传递给可变参数模板函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个带有名为enqueue的函数的类:

  template< class T,class ... Args> 
内联自动ThreadPool :: enqueue(T& t,Args& amp; ... args)-> std :: future< typename std :: result_of< T(Args ...)> :: type>
{
using return_type = typename std :: result_of< T(Args ...)> :: type;

自动任务= std :: make_shared< std :: packaged_task< return_type()>> (
std :: bind(std :: forward< T(t),std :: forward< Args>(args)...)
);

std :: future< return_type>结果= task-> get_future();
{
std :: unique_lock< std :: mutex>锁(m_mutex);

//停止池后不允许创建工作。
if(m_done)
throw std :: runtime_error(在已停止的线程池上排队。);

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

m_cond.notify_one();
m_futures.push_back(move(result));
的返回结果;
}

这是在ThreadPool类旁边的头文件内部完成的内联实现。



这是一个单例,应该能够使用带有其参数的任何函数,将其添加到任务队列中,并返回该函数的结果类型的将来。 / p>

这是我尝试使用的类:

  void Grepper :: scan(std :: tr2 :: sys :: path const&文件夹,std :: string表达式,bool verbose){
//创建目录迭代器。
std :: tr2 :: sys :: recursive_directory_iterator d(文件夹);
std :: tr2 :: sys :: recursive_directory_iterator e;

//从与初始扩展名列表匹配的文件中创建任务。
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(),表达式,详细);
}
}
}

哪个给出了编译器错误:

 错误C3867'Grepper :: grep':非标准语法;使用'&'创建指向成员

的指针以及将函数作为lambda传递:

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

这给了我以下编译器错误:

 错误C2893无法专门化功能模板'unknown-type std :: invoke(_Callable&&,_ Types&& ...)'

作为参考,这里是我的grep方法的声明:

  void grep(std :: tr2 :: sys :: path文件,std ::字符串表达式,bool verbose); 

如何正确地将此函数及其参数传递给enqueue方法?

解决方案

尝试使用成员函数指针失败的原因有两个:


  1. 要形成指向成员函数的指针,您需要使用& Grepper :: grep 语法。

  2. 成员函数需要一个隐式对象参数(以及其他参数,以便它也可以由 std :: bind std :: result_of正确处理) )。

话虽如此,您可以尝试以下呼叫:

  ThreadPool :: get_instance()。enqueue(
& Grepper :: grep
,此
,d-> ; path()
,表达式
,详细
);

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

根据您的设计,这些参数应在调用入队:

  ThreadPool :: get_instance()。enqueue(
[this] (std :: tr2 :: sys :: path p,std :: string s,bool b){grep(p,s,b);}
,d-> path()
,表达式
,冗长的
);

或由lambda表达式捕获,因此没有其他 Args 是必需的:

  ThreadPool :: get_instance()。enqueue(
[this,d,expression ,verbose] {grep(d-> path(),expression,verbose);}
);


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?

解决方案

The attempt with a pointer to a member function fails for two reasons:

  1. To form a pointer to a member function, you need to use &Grepper::grep syntax.
  2. A member function requires an implicit object parameter (among other arguments, so that it can be also properly handled by std::bind and std::result_of).

Having said that, you could try the following call:

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

The attempt with a lambda expression fails, because that lambda expression passed as an argument:

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

declares three parameters, so the Args parameter pack must not be empty. But it is in your case:

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

Those arguments, according to your design, should be either passed in a call to enqueue:

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

or captured by a lambda expression, so that no additional Args are needed:

ThreadPool::get_instance().enqueue(
    [this,d,expression,verbose] { grep(d->path(), expression, verbose); }
);

这篇关于将成员函数传递给可变参数模板函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆