在C ++ 17中替换已删除的bind1st

时间:2018-10-11 21:17:30

标签: c++ c++17

我曾经使用过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);

4 个答案:

答案 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