我曾经使用过bind1st
,但是随着bind1st
被删除,我将项目升级到C ++ 17。
如何在以下语句中替换bind1st
?
Lambda?
DBManager::Instance().FuncQuery(std::bind1st(std::mem_fn(&CGuild::LoadGuildData), this), "SELECT master, level, exp, name, skill_point, skill, sp, ladder_point, win, draw, loss, gold FROM guild WHERE id = %u", m_data.guild_id);
答案 0 :(得分:5)
使用lambda,您可以替换
std::bind1st(std::mem_fn(&CGuild::LoadGuildData), this)
作者
[this](auto&& data) {return this->LoadGuildData(data);}
最后给出类似的内容:
DBManager::Instance().FuncQuery(
[this](auto&& data) {return this->LoadGuildData(data);},
"SELECT master, level, exp, name, skill_point, skill, sp, "
"ladder_point, win, draw, loss, gold FROM guild WHERE id = %u",
m_data.guild_id);
答案 1 :(得分:3)
只需使用std::bind:
std::bind(std::mem_fn(&CGuild::LoadGuildData), this, std::placeholders::_1)
您也可以删除多余的std::mem_fn
:
std::bind(&CGuild::LoadGuildData, this, std::placeholders::_1)
答案 2 :(得分:2)
您可以在这里做两件事。我感到非常不幸的是,当前的局势如此尴尬。
最直接的替代方法是将您的bind1st
正确地转换为bind
:
std::bind(&CGuild::LoadGuildData, this, std::placeholders::_1)
或者,如果您半定期使用bind
,则可能会以某种形式通过using
引入占位符,因此变为:
std::bind(&CGuild::LoadGuildData, this, _1)
这实际上比bind1st
更好,因为它可以转发其论点,但bind1st
不能。
我们可以做的另一件事是lambda。在这里,这取决于LoadGuildData
的确切功能。如果它返回一个对象,并且您不必在乎如何使用此绑定的可调用对象,则只需编写:
[this](auto const& arg){ return LoadGuildData(arg); }
大多数情况下,这将起作用。但这与绑定表达式不完全相同。如果LoadGuildData()
返回了类似int&
的内容,则绑定表达式将返回int&
,但是此版本将返回int
。那可能并不重要。可能不是。但如果是这样,则必须至少添加:
[this](auto const& arg) -> decltype(auto) { return LoadGuildData(arg); }
这将返回引用类型,也可能不会返回引用类型,具体取决于LoadGuildData
实际返回的内容。
现在...自变量arg
可能需要作为可修改的引用,这是必需的
[this](auto&& arg) -> decltype(auto) { return LoadGuildData(arg); }
但是经常,您可能需要更多。您可能需要在需要检查它是否可调用的上下文中使用此可调用对象。现在,由于这种检查的工作原理,我编写的所有lambda都声称它们可以与任何参数一起调用。无论LoadGuildData
实际需要做什么。但是,如果类型错误,则会出现硬编译错误。不幸的。
因此,编写与我先前编写的绑定表达式具有相同行为的lambda真正需要做的是:
[this](auto&& arg) -> decltype(LoadGuildData(std::forward<decltype(arg)>(arg))) {
return LoadGuildData(std::forward<decltype(arg)>(arg)));
}
实际上,这不是完全相同的行为。该lambda实际上在某些方面更好-因为如果LoadGuildData
是成员函数模板或重载集或采用默认参数,则bind表达式将不起作用-但lambda在所有这些情况下均有效。这就是为什么经常建议使用lambda的原因-它们始终有效,通常是最好的解决方案,有时是唯一的解决方案。
但这是一个很大的问题,这就是为什么这么多代码库都使用宏的原因。像BOOST_HOF_RETURNS
:
#define FWD(...) static_cast<decltype(__VA_ARGS__)&&>(__VA_ARGS__)
[this](auto&& arg) BOOST_HOF_RETURNS(LoadGuildData(FWD(arg)))
所有这些都是说...我们不能拥有美好的事物。
答案 3 :(得分:1)
我只会使用lambda,而跳过使用bind
,因为这似乎也已被弃用。
我们可以从已弃用bind1st
的提案n4190中,在III. What Must Die
部分中说:
D.9“活页夹” [depr.lib.binders]
这定义了bind1st()/ bind2nd(),被严格取代 bind()。 (将来,我认为bind()本身已经 由lambda(尤其是通用lambda)取代,因此bind()应该 被弃用,但这不是此建议的一部分。)
请注意文档Changes between C++14 and C++17告诉我们哪些提案不推荐使用。
所以看起来像:
[this](...) {return this->LoadGuildData(...);}. // ... needs to be filled in based
// on implementation