根据函数签名将变量模板中的类型转发为值/引用
Forward types in variadic template as values/references according to function signature
这个问题与这个、这个以及潜在的这个有关。
我有以下类,其中AddFunction
方法接收一个函数和该函数的参数列表,然后生成一个std::thread
,用传递的参数调用传递的函数:
class Processes {
public:
Processes() {}
~Processes() {
for (auto &t : threads_) {
t.join();
}
}
template <class Function, typename... Args>
void AddFunction(Function &&func, Args &&... args) {
threads_.emplace_back(std::forward<Function>(func),
std::forward<Args>(args)...);
}
private:
std::vector<std::thread> threads_;
}
这将导致每个参数都有一个副本,如果对象不可复制,则编译将失败,因为std::thread
要求引用封装在std::ref
中,以确保此对象将超过线程的生存期,否则将复制它。
当在目标函数签名中指定时,我希望通过引用传递对象。
我试着使用lambda:
template <class Function, typename... Args>
void AddFunction(Function &&func, Args &&... args) {
threads_.emplace_back([&]() { func(std::forward<Args>(args)...); });
}
但这会导致不正确的行为,因为lambda在按值传递值之前先通过引用捕获值,从而导致按引用捕获行为。
如何实现根据目标函数签名将参数转发为值或引用的函数?
示例:
void Foo(int a, std::vector<int> const &b) { /* ... */ }
int main() {
Processes procs;
int a = 6;
std::vector<int> b;
procs.AddFunction(
Foo,
a, // Should be passed by value
b // Should be passed by reference (as implemented by std::ref)
);
return 0;
}
您可以将函数签名更改为不太通用的:
第一批助手:
template <typename T> struct non_deducible { using type = T; };
template <typename T> using non_deducible_t = typename non_deducible<T>::type;
template <typename T>
auto passed_by(T& t, std::true_type)
{
return std::ref(t);
}
template <typename T>
T&& passed_by(T&& t, std::false_type)
{
return std::forward<T>(t);
}
然后
template <class Ret, typename... Args>
void AddFunction(Ret (*func)(Args...), non_deducible_t<Args>... args) {
threads_.emplace_back(func,
passed_by(std::forward<Args>(args),
std::is_reference<Args>{})...);
}
如果你想走lambda路线,你可以实现一些实用程序,允许你通过"完美向前"捕获-这意味着右值被移动到闭包中,左值被引用捕获。您可以使用std::tuple<T>
来存储T
或T&
(我的链接文章有一个更干净的实现):
template <class Function, typename... Args>
void AddFunction(Function &&func, Args &&... args)
{
threads_.emplace_back([
targs = std::tuple<Args...>{std::forward<Args>(args)...},
tfunc = std::tuple<Function>(func)]() mutable
{
std::apply([&targs](auto&& x_func)
{
std::apply([&x_func](auto&&... x_args)
{
std::forward<Function>(x_func)(
std::forward<Args>(x_args)...
);
}, targs);
}, tfunc);
});
}
活动魔杖盒示例
相关文章:
- 通过类型别名从构造函数转发模板推导
- 类似函数的化简函数中的转发和返回类型
- 自定义类型转换运算符在转发引用上调用时不起作用(当对象按值传递时有效)
- 在完美转发函数中公开参数类型,避免代码重复
- 如何构造一个 std::variant 类型对象,其自身 Templated 和构造函数转发参数
- 创建参数并从可变参数类型模板转发
- 有没有办法在不引用其模板类型的情况下转发声明指向类的指针
- 从转发函数类型推断的模板化返回类型
- 转发非引用类型的引用
- 根据函数签名将变量模板中的类型转发为值/引用
- 是否可以在没有类型推断的情况下实现类似转发引用的行为
- 使用确定类型转发引用行为
- 类类型作为参数,类转发
- 将参数从模板转发到不同类型的函数
- 可以转发声明的类型模板参与模板专门化
- 基元类型的完美转发
- 如何使用可变参数模板转发类型和值模板参数
- 如何避免在转发声明导致不完整类型错误时在头文件中 #include
- 使用 C++ 中类中的类型进行转发
- 容器/类型名称转发的递归模板类型