这是我的情况:
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
仅接受非const
左值引用。我应该如何强制执行此操作?
答案 0 :(得分:35)
我想确保模板参数F&amp;&amp; f只接受非常量左值参考。
然后你不应该使用转发参考。转发的整个想法是接受任何值类别并保留它以供将来调用。所以第一个修复是不要在这里使用错误的技术,而是通过左值引用来接受:
template<typename T, typename F>
inline
auto do_with(T&& rvalue, F& f) {
// As before
}
如果你尝试将rvalue传递给函数,那么应该让编译器很好地抱怨。它不会阻止编译器允许const左值(F
将推导为const F1
)。如果你真的想要阻止它,你可以添加另一个重载:
template<typename T, typename F>
inline
void do_with(T&& , F const& ) = delete;
F const&
的参数类型将更好地匹配const lvalues(以及rvalues,btw),因此这个将在重载决策中被选中,并立即导致错误,因为它的定义被删除。非常量左值将被路由到您要定义的函数。
答案 1 :(得分:12)
您可以通过左值参考获取f
并使用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");
…
}
在C ++ 20中引入constraints后,您将能够使用requires
子句:
template<typename T, typename F>
inline
auto do_with(T&& rvalue, F& f) requires !std::is_const_v<F> {
…
}
答案 2 :(得分: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) {
}