为什么通过通用引用运算符 (&&) 将变量的引用传递给 Varadic 模板函数失败?
why pass reference of a varaible to a varadic template function by universal reference operator (&&) failed?
我打算将变量的引用传递到成员函数指针中,该指针是另一个模板函数的参数,用于调用类的任何类型的成员函数,但从打印结果来看,它不是通过引用传递的,而只是通过值传递。
#include <functional>
#include <iostream>
#include <memory>
template <class WorkerType> class Delegate {
public:
template <typename... Args>
using WrkFunc = void (WorkerType::*)(Args... args);
explicit Delegate(WorkerType &wrk) : m_worker(&wrk) {}
template <typename... Args>
void workerDo(WrkFunc<Args...> func, Args &&... args) {
auto fn = std::bind(func, m_worker.get(), std::forward<Args>(args)...);
fn();
}
private:
std::shared_ptr<WorkerType> m_worker;
};
class SomeWorker {
public:
SomeWorker() = default;
void doSomething(int &a) {
a = 1000;
std::cout << "2# address: " << &a << ", value: " << a << std::endl;
}
};
int main() {
SomeWorker wrk;
Delegate<SomeWorker> del(wrk);
int a = 0;
std::cout << "1# address: " << &a << ", value: " << a << std::endl;
del.workerDo(&SomeWorker::doSomething, a);
std::cout << "3# address: " << &a << ", value: " << a << std::endl;
return 0;
}
我期望的结果是这样的:1# 地址:0x7fffc1dc621c,值:0 2# 地址:0x7fffc1dc621c,值:10003# 地址:0x7fffc1dc621c,值:1000
但实际结果是:1# 地址:0x7fffc1dc621c,值:0 2# 地址:0x7fffc1dc61d0,值:1000
3# 地址:0x7fffc1dc621c,值:0
首先,Delegate
类的构造函数完全损坏。这是对std::shared_ptr
的错误用法。您应该像下面这样修复:
// define
explicit Delegate(std::shared_ptr<WorkerType> wrk) : m_worker(std::move(wrk)) {}
//call
Delegate<SomeWorker> del(std::make_shared<SomeWorker>());
要将对象左值引用传递给std::bind
,必须使用std::ref
。
如何通过引用将函数绑定到对象?
当你std::ref
结果传递给workerDo
时,WrkFunc
会干扰调用。
因此,您需要使用std::is_invocable_r_v
重写类型检查
#include <functional>
#include <iostream>
#include <memory>
#include <type_traits>
template <class WorkerType> class Delegate {
public:
explicit Delegate(std::shared_ptr<WorkerType> wrk) : m_worker(std::move(wrk)) {}
template <typename Func, typename ...Args, std::enable_if_t<std::is_invocable_r_v<void, Func, WorkerType, Args...>, std::nullptr_t> = nullptr>
void workerDo(Func func, Args && ...args) {
auto fn = std::bind(func, m_worker.get(), std::forward<Args>(args)...);
fn();
}
private:
std::shared_ptr<WorkerType> m_worker;
};
class SomeWorker {
public:
SomeWorker() = default;
void doSomething(int &a) {
a = 1000;
std::cout << "2# address: " << &a << ", value: " << a << std::endl;
}
};
int main() {
Delegate<SomeWorker> del(std::make_shared<SomeWorker>());
int a = 0;
std::cout << "1# address: " << &a << ", value: " << a << std::endl;
del.workerDo(&SomeWorker::doSomething, std::ref(a));
std::cout << "3# address: " << &a << ", value: " << a << std::endl;
return 0;
}
https://wandbox.org/permlink/fnBThXw5Uh72JeGQ
有什么方法可以避免使用std::ref到处打电话给workerDo?
使用如下所示的包装器函数将解决。
template <class T, class U, std::enable_if_t<
(std::is_lvalue_reference_v<T> ? std::is_lvalue_reference_v<U> : true) &&
std::is_convertible_v<std::remove_reference_t<U>*, std::remove_reference_t<T>*>,
std::nullptr_t
> = nullptr>
inline decltype(auto) forward_or_construct_reference_wrapper(U&& u)
{
if constexpr(std::is_lvalue_reference_v<T>) {
return std::reference_wrapper{std::forward<T>(u)};
}
else {
return static_cast<T&&>(u);
}
}
https://wandbox.org/permlink/wli9Dh9vXSjzBWMA
相关文章:
- 将对象数组的引用传递给函数
- 什么时候在C++中返回常量引用是个好主意
- 我想将一个对T类型的非常量左值引用绑定到一个T类型的临时值
- 何时在引用或唯一指针上使用移动语义
- 如何在c++中使用引用实现类似python的行为
- 编译C++时未定义的引用
- Ctypes wstring通过引用传递
- c++r值引用应用于函数指针
- 理解c++中的引用
- C++取消引用指针.为什么会发生变化
- 如何修复此错误:未定义对"距离(浮点数,浮点数,浮点数,浮点数,浮点数)"的引用
- 我的项目不会像"undefined reference to `grpc::g_core_codegen_interface'"那样使用未定义的引用错误进行编译
- C++Boost Asio Pool线程,带有lambda函数和传递引用变量
- 强制转换为引用类型
- 引用一个已擦除类型(void*)的指针
- 向量元素的引用地址与它所指向的向量元素的地址不同.为什么
- 具有默认值的引用获取函数
- 如何使用基类指针引用派生类成员
- 使用取消引用的指针的多态性会产生意外的结果.为什么?
- 为什么通过通用引用运算符 (&&) 将变量的引用传递给 Varadic 模板函数失败?