У меня была эта простая функция:
template <class F>
F lockAndDo(F &&fct)
{
std::unique_lock<std::mutex> lock{_mutex};
return fct();
}
Для которого я мог бы передать лямбда-функции, как это:
int value = LockAndDo([&] {
return _collection.size();
});
Проблема в том, что иногда мне нужно было передать функцию void лямбда, и компилятор хвастался, что я пытался вернуться из функции void лямбда.
Затем я должен был сделать это разделение для пустых и не пустых лямбда-функций
template <class F>
F lockAndDoAndReturn(F &&fct)
{
std::unique_lock<std::mutex> lock{_mutex};
return fct();
}
template <class F>
void lockAndDo(F &&fct)
{
std::unique_lock<std::mutex> lock{_mutex};
fct();
}
Есть ли лучший подход, который я могу использовать, чтобы создать только одну функцию, а не две, которые делают то же самое?
2 ответа
Вам может понадобиться достаточно свежая версия C ++, которая, я надеюсь, является обычной практикой.
Я думаю, у вас есть несколько вариантов, в зависимости от поведения, которое вы хотите.
Если вы хотите вернуть по значению, используйте auto
в качестве типа возврата:
template <class F>
auto lockAndDo(F &&fct)
{
std::unique_lock<std::mutex> lock{_mutex};
return std::invoke(fct);
}
Если вы разрешите возвращать ссылки, это не сработает, и вам понадобится decltype(auto)
.
template <class F>
decltype(auto) lockAndDo(F &&fct)
{
std::unique_lock<std::mutex> lock{_mutex};
return std::invoke(fct);
}
Имейте в виду, что теперь вам все еще требуются функции void. Это также можно решить:
template <class F, class ...A>
decltype(auto) lockAndDo(F &&fct, A &&...a)
{
std::unique_lock<std::mutex> lock{_mutex};
return std::invoke(fct, std::forward<A>(a)...);
}
И, как вы могли заметить, я использовал std::invoke
во всех примерах, поскольку он поддерживает все виды вызовов. Это включает в себя указатели на функции-члены ...
Оставьте на усмотрение читателя: вы можете сделать свою функцию условно никакой, если только вы не заботитесь об этом.
Вы можете сделать тип возврата auto
(или {{X1 }}, в зависимости от сценариев (см. дополнительную информацию на связанной странице), что будет определяться оператором return.
(since C++14)
в типе возврата функции или лямбда-выражения:auto& f();
. Тип возврата выводится из операнда его оператора возвратаnon-discarded (since C++17)
.
Например
template <class F>
auto // determined by the return type of `F`, including `void`
lockAndDo(F &&fct)
{
std::unique_lock<std::mutex> lock{_mutex};
return fct();
}
Похожие вопросы
Новые вопросы
c++
C++ — это язык программирования общего назначения. Изначально он разрабатывался как расширение C и имел аналогичный синтаксис, но теперь это совершенно другой язык. Используйте этот тег для вопросов о коде, который будет скомпилирован с помощью компилятора C++. Используйте тег версии для вопросов, связанных с конкретной стандартной версией [C++11], [C++14], [C++17], [C++20] или [C++23]. и т.д.