如何为 std::bind 制作包装
How to make a wrap for std::bind?
我正在构建一个简单的类来执行原子操作,但是当我尝试调用该方法时出现错误call
#include <iostream>
#include <string>
#include <mutex>
#include <functional>
template<typename _Tp>
class Atom {
_Tp val_;
std::mutex mtx_;
public:
Atom() = default;
~Atom() = default;
Atom(const Atom&) = delete;
Atom& operator=(const Atom&) = delete;
Atom& operator=(const Atom&) volatile = delete;
// FIXME:
template<typename Ret, typename... _Args>
Ret call(_Tp&& f, _Args&&... args) {
mtx_.lock();
auto b_fn = std::bind(static_cast<Ret(_Tp::*)(_Args...)>(f),
std::ref(val_), std::forward<_Args>(args)...);
Ret r = b_fn();
mtx_.unlock();
return r;
}
operator _Tp() {
return load();
}
_Tp operator= (_Tp val) {
store(val);
return val;
}
_Tp load() {
_Tp tmp;
mtx_.lock();
tmp = val_;
mtx_.unlock();
return tmp;
}
void store(_Tp val) {
mtx_.lock();
val_ = val;
mtx_.unlock();
}
};
我尝试这样使用:
int main(int argc, char **argv) {
Atom<std::string> str;
str = "asdf";
// FIXME:
str.call(&std::string::append, std::string("test"));
std::string ot = str;
std::cout << ot << std::endl;
return 0;
}
错误:
error: no matching function for call to ‘Atom<std::basic_string<char> >::call(<unresolved overloaded function type>, std::string)’
str.call(&std::string::append, std::string("test"));
问题不在于包装std::bind()
是谁,而在于如何获取重载 [member] 函数的地址!因为当您尝试使用std::bind()
时,您会遇到完全相同的问题。
您尝试执行的操作实际上存在问题:
-
您尝试获取重载 [成员] 函数的地址。编译器将允许如果地址立即与确定确切类型的东西一起使用,例如,通过将其传递给采用适当 [member] 函数指针的函数或通过强制转换它。如果不是因为第二个问题,你可以使用这样的东西:
static_cast<std::string& (std::string::*)(std::string)>(&std::String::append)
强制转换将推断正在使用哪个过载。
-
该标准明确允许标准库实现类的任何非
virtual
成员函数和类模板,以采用任意默认的附加参数。但是,在获取其中一个的地址时,您需要知道确切的参数才能匹配 [member] 函数指针。
因此,尝试std::bind()
标准C++库中类的成员之一既相当冗长又不可移植。最简单的方法可能是只使用 lambda 函数:
std::string test("test")
str.call([=](std::string& s){ return s.append(test); });
(显然,对于附加字符串文字,您不需要额外的变量,但我想提供一个非空闭包的示例(。另一种方法是创建一个合适的函数对象并将其传递给它,而不是尝试指向成员函数的指针:
struct append {
template <typename... Args>
auto operator()(std::string& s, Args&&.. args) const
-> decltype(s.append(std::forward<Args>(args)...)) {
return s.append(std::forward<Args>(args)...);
}
};
str.call(append(), std::string("test));
我意识到这两种方法都不像您希望的那样方便,但目前C++没有很好的方法来创建像上面这样的函数对象。如果我们有一些东西,那就太好了,但我什至不知道相应的建议。
顺便说一句,您的call()
函数仍然不起作用,因为那里没有任何适当的推断返回类型Ret
.此外,即使它有效,它似乎也会创建函数对象,该对象将修改应该受保护的共享对象,而无需在调用时同步。您可能只想在持有锁的同时应用传递的函数对象(请注意,在持有锁的同时应用未知代码通常是一个坏主意,因为它在被调用的代码返回并尝试通过不同的路由访问对象时打开了创建死锁的机会(。
- POCO::PostgreSQL:如何将std::vector支持添加到`Binder::bind`
- 如何在c++17中制作一个模板包装器/装饰器
- std::vector的包装器,使数组的结构看起来像结构的数组
- 如何在c++迭代器类型中包装std::chrono
- 是否可以用"iostream"包装现有的TCP/OOpenSSL会话
- 用pybind11包装C++抽象类时出错
- 为左值和右值的包装器实现C++范围
- C结构,其指针将被包装在unique_ptr中
- 如何包装第三方DLL在R中使用
- 在类型和包装器之间reinterpret_cast是否安全<Type>?
- 将 N-arg 函数包装到另一个函数中
- 元组由 Swig 生成的 Python 包装器返回,用于C++向量
- 包装一个对象并假装它是一个 int
- 使用 Python Extension API 包装复杂C++类
- 外壳包装器句柄/执行交互式命令管道C++ UNIX
- 为 std::bind 创建模板包装器
- 如何为 std::bind 制作包装
- 如何使用boost::bind来创建函数包装器
- 在std::bind中包装lambda以捕获r值
- 如何将函数(std::bind)包装到名称空间中