Замена удаленного bind1st в C ++ 17 - PullRequest
0 голосов
/ 12 октября 2018

У меня было это использование bind1st, но я обновляю свой проект до C ++ 17, так как bind1st удаляется.

Как я могу заменить bind1st в следующем утверждении?Лямбда?

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 голосов
/ 12 октября 2018

Здесь можно сделать две вещи.И мне очень жаль, что нынешнее положение дел так неловко.

Самая прямая замена - это взять bind1st и преобразовать его точно в bind:

std::bind(&CGuild::LoadGuildData, this, std::placeholders::_1)

Или, если вы используете bind регулярно, вы, вероятно, внесетезаполнители через using в той или иной форме, так что это становится:

std::bind(&CGuild::LoadGuildData, this, _1)

Это на самом деле строго лучше, чем bind1st, так как это передает свой аргумент, но bind1st не будет.

Другая вещь, которую мы могли бы сделать, это лямбда.И здесь все зависит от того, что именно делает LoadGuildData.Если он возвращает объект, и вас не волнует, как обязательно используется этот ограниченный вызываемый объект, вы можете просто написать:

[this](auto const& arg){ return LoadGuildData(arg); }

В большинстве случаев это будет работать.Но это не совсем то же самое, что выражение bind.Если LoadGuildData() вернет что-то вроде int&, выражение привязки вернет int&, но эта версия вернет int.Это может быть не важно.Это может быть не так.Но если это так, вы должны добавить, по крайней мере:

[this](auto const& arg) -> decltype(auto) { return LoadGuildData(arg); }

Это будет либо возвращать ссылочный тип, либо не ссылочный тип в зависимости от того, что на самом деле возвращает LoadGuildData.

Теперь... аргумент, arg, может потребоваться для модифицируемой ссылки, что требует

[this](auto&& arg) -> decltype(auto) { return LoadGuildData(arg); }

Но достаточно часто вам может понадобиться что-то большее.Возможно, вам придется использовать этот вызываемый в контексте, который должен проверить, если это вызываемый.Прямо сейчас, из-за правил, как работает эта проверка - все лямбды, которые я написал, будут утверждать, что они могут быть вызваны любым аргументом вообще.Независимо от того, что на самом деле LoadGuildData.Но если это неправильный тип, вы получите серьезную ошибку компиляции.Несчастная.

Итак, что вам действительно нужно сделать, чтобы написать лямбду, которая будет иметь то же поведение, что и выражение связывания, которое я написал ранее:

[this](auto&& arg) -> decltype(LoadGuildData(std::forward<decltype(arg)>(arg))) {
    return LoadGuildData(std::forward<decltype(arg)>(arg)));
}

На самом деле, это не совсем то же самое поведение,Эта лямбда на самом деле лучше в некоторых отношениях - потому что выражение привязки не сработало бы, если бы LoadGuildData было шаблоном-функцией-членом или набором перегрузки или приняло аргумент по умолчанию - но лямбда работает во всех этих случаях.Вот почему так часто рекомендуют использовать лямбды - они всегда работают, они обычно являются лучшим решением, и иногда они являются единственным решением.

Но это огромный глоток, поэтому многие базы кода используют макросы.Как BOOST_HOF_RETURNS:

#define FWD(...) static_cast<decltype(__VA_ARGS__)&&>(__VA_ARGS__)
[this](auto&& arg) BOOST_HOF_RETURNS(LoadGuildData(FWD(arg)))

Все это говорит о том, что ... у нас не может быть хороших вещей.

0 голосов
/ 12 октября 2018

С лямбдой вы можете заменить

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);
0 голосов
/ 12 октября 2018

Я бы просто пошел с лямбдами и пропустил, используя bind, так как это, вероятно, также устарело.

Мы можем из предложения, что устарело bind1st, что n4190 в разделе III. What Must Die:

D.9 "Связующие" [depr.lib.binders]

Это определяет bind1st () / bind2nd (), который были строго заменены bind () .(В будущем я буду утверждать, что сама функция bind () была заменена лямбдами и особенно общими лямбдами, поэтому bind () не рекомендуется , но это не является частью этого предложения.)

Обратите внимание на документ Изменения между C ++ 14 и C ++ 17 говорят нам, какие предложения устарели, какие.

Так что это будет выглядеть примерно так:

[this](...) {return this->LoadGuildData(...);}. // ... needs to be filled in based
                                                // on implementation
0 голосов
/ 12 октября 2018

Просто используйте std :: bind :

std::bind(std::mem_fn(&CGuild::LoadGuildData), this, std::placeholders::_1)

И вы также можете удалить лишние std::mem_fn:

std::bind(&CGuild::LoadGuildData, this, std::placeholders::_1)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...