【问题标题】:In C++, how do I add an argument to an "Args&&... args" list of arguments?在 C++ 中,如何将参数添加到“Args&&... args”参数列表?
【发布时间】:2018-10-21 00:21:09
【问题描述】:

我有自己的线程实现,它允许我管理与我的线程通信的各种方式。它基于 C++ std::thread 类。

我创建线程来运行名为run() 的函数,该函数调用用户函数。我想做的是调用用户函数,包括我的线程对象指针。

构造函数中存在问题。我想传递构造函数中指定的Args 并将this 添加到该列表中:

class safe_thread
{
public:
    typedef std::shared_ptr<safe_thread>    pointer_t;
    typedef std::vector<pointer_t>          vector_t;

    template<class Function, class... Args>
    safe_thread(Function&& f, Args&&... args)
        : f_function([this, f, args...]{ std::bind(f, this, args...)(); })
    {
[...snip...]

private:
    std::function<void()>               f_function;
};

// I use that constructor with two different types of signatures:
//
// 1. member function
//
safe_thread listen(&my_other_class::some_function, this);

// 2. static function
//
safe_thread worker(&my_static_function);

std::bind() 不理解我当前的语法。它需要一个函数 (f) 和 args...。那么,我如何更改 args... 以包含 this

【问题讨论】:

  • 为什么在这里使用bindf(this, args...); 完全有效。
  • 此外,即使使用绑定,语法似乎也是正确的。你确定你传递了正确数量的参数吗?
  • @MilesBudnek,如果我用std::bind() 调用safe_thread 因为我想调用一个成员函数,直接f(...) 会失败并出现error: must use '.*' 或'->*' 在 'f (...)' 中调用指向成员函数的指针,例如'(... ->* f) (...)'
  • 所以fsafe_thread 的指向成员函数的指针(您试图将其绑定以传递this [a safe_thread*] 作为第一个参数)?这似乎不对。
  • 如果f 是一个成员函数指针,其this 已在args... 中提供,则在args... 之前注入不同的this 将失败。基本上,上面的代码中有足够多的错误内容,并且(由您自己)对您需要 minimal reproducible example 的问题的误解。搞砸绑定或类似操作时出现的错误是不透明的,所以当你描述出了什么问题时,我只是相信你。

标签: c++ arguments variadic-functions


【解决方案1】:

对于那些感兴趣的人,我实际上找到了一个解决方案,即将this 参数移动到列表的末尾。这样我的std::invoke() 到成员函数或标准静态函数的工作方式相似:

f_function([this, f, args...]{ std::invoke(f, args..., this)(); })

如果不这样做,正如 Miles Budnek 所说,将需要加载 SFINAE 才能知道 f 是成员函数还是普通函数。

问题在于,在某些情况下,我会在成员函数中创建线程,而在其他情况下,我会从静态函数中创建线程。

对于成员函数,args... 列表中的第一个参数是调用者的this,显然this 不能作为下一个参数移过来。

实际上,我的第一次尝试是生成这个:

std::invoke(
    &my_other_class::some_func,     // correct
    safe_thread::this,              // wrong 'this' (i.e. safe_thread)
    my_other_class::this,           // 'this' for function, wrong location
    ...);                           // other parameters

通过更改调用顺序,我现在可以在正确的位置获得正确的“this”:

std::invoke(
    &my_other_class::some_func,     // correct
    my_other_class::this,           // 'this' for function, correct location
    ...,                            // other parameters
    safe_thread::this);             // 'this' to safe_thread

显然,这意味着我必须修复被调用函数的签名,但我可以接受。


正如 tkausl 所述,std::bind() 不是必需的。有关详细信息,请参阅 cmets。话虽如此,std::invoke() 是 C++17,所以如果你还在使用旧版本,你可能不得不坚持使用std::bind()

【讨论】:

  • std::bind 的意义何在?您可以直接拨打std::invoke
  • 好点。起初我想将绑定保存在f_function 中,但是如果不使我的类成为模板(返回类型取决于输入参数),我看不到如何确定类中的类型。所以是的,std::invoke() 工作得很好。我会更新我的答案。
猜你喜欢
  • 2020-11-06
  • 2021-12-24
  • 1970-01-01
  • 2011-11-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多