如何强制函数仅接受左值引用参数

时间:2018-06-14 08:01:17

标签: c++ templates

这是我的情况:

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左值引用。我应该如何强制执行此操作?

3 个答案:

答案 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_assertis_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) {

}