Как заставить функцию принимать только опорный параметр lvalue
Вот моя ситуация:
template<typename T, typename F>
inline
auto do_with(T&& rvalue, F&& f) {
auto obj = std::make_unique<T>(std::forward<T>(rvalue));
auto fut = f(*obj);
return fut.then_wrapped([obj = std::move(obj)] (auto&& fut) {
return std::move(fut);
});
}
Я хочу, чтобы параметр шаблона F&& f
принимал только ссылку non- const
lvalue. Как я должен применять это?
Ответы
Ответ 1
И я хочу, чтобы параметр шаблона F && f принимал только ссылку на константу lvalue.
Тогда вы не должны использовать ссылку пересылки. Вся идея пересылки - принять любую категорию значений и сохранить ее для будущих вызовов. Поэтому первое исправление заключается в том, чтобы не использовать здесь неправильную технику и вместо этого принимать ссылку на lvalue:
template<typename T, typename F>
inline
auto do_with(T&& rvalue, F& f) {
// As before
}
Это должно заставить компилятор жаловаться, если вы попытаетесь передать значение r функции в функцию. Это не остановит компилятор от разрешения const lvalues, хотя (F
будет выведено как const F1
). Если вы действительно хотите предотвратить это, вы можете добавить еще одну перегрузку:
template<typename T, typename F>
inline
void do_with(T&& , F const& ) = delete;
Тип параметра F const&
будет лучше соответствовать константам lvalues (и rvalues тоже, btw), поэтому этот будет выбран в разрешении перегрузки и сразу же вызовет ошибку, поскольку его определение будет удалено. Неконсольные lvalues будут перенаправлены на функцию, которую вы хотите определить.
Ответ 2
Вы можете взять f
по ссылке lvalue и предотвратить неконстантные значения с static_assert
и is_const
:
template<typename T, typename F>
inline
auto do_with(T&& rvalue, F& f) {
static_assert(!std::is_const<F>::value, "F cannot be const");
…
}
С введением ограничений в С++ 20, вы будете иметь возможность использовать requires
пункт вместо того, чтобы:
template<typename T, typename F>
inline
auto do_with(T&& rvalue, F& f) requires !std::is_const_v<F> {
…
}
Ответ 3
добавить еще одно решение
template<typename T, typename F>
inline
auto do_with(T&& rvalue, F&& f) {
static_assert(!std::is_const<typename std::remove_reference<F>::type>::value, "must be non-const");
static_assert(std::is_lvalue_reference<F>::value, "must be lvalue reference");
...
}
или с SFINAE
template<typename T, typename F, typename std::enable_if<!std::is_const<typename std::remove_reference<F>::type>::value && std::is_lvalue_reference<F>::value, int>::type = 0>
inline
auto do_with(T&& rvalue, F&& f) {
}