How to force a function to only accept an lvalue r

2020-06-30 12:13发布

Here's my situation:

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);
    });
}

I want to make sure the template parameter F&& f only accepts a non-const lvalue reference. How should I enforce this?

标签: c++ templates
3条回答
Explosion°爆炸
2楼-- · 2020-06-30 12:17

And I want to make sure template parameter F&& f only accept a non-const lvalue reference.

Then you should not have used a forwarding reference. The whole idea of forwarding is to accept any value category and preserve it for future calls. So the first fix is to not use the wrong technique here, and accept by an lvalue reference instead:

template<typename T, typename F>
inline
auto do_with(T&& rvalue, F& f) {
  // As before
}

That should make the compiler complain nicely if you attempt to pass an rvalue into the function. It won't stop the compiler from allowing const lvalues though (F will be deduced as const F1). If you truly want to prevent that, you can add another overload:

template<typename T, typename F>
inline
void do_with(T&& , F const& ) = delete;

The parameter type of F const& will match const lvalues better (and rvalues too, btw), so this one will be picked in overload resolution, and immediately cause an error because its definition is deleted. Non-const lvalues will be routed to the function you want to define.

查看更多
我命由我不由天
3楼-- · 2020-06-30 12:28

You can take f by lvalue reference and prevent non-const values with static_assert and 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");
    …
}

With the introduction of constraints in C++20, you will be able to use a requires clause instead:

template<typename T, typename F>
inline
auto do_with(T&& rvalue, F& f) requires !std::is_const_v<F> {
    …
}
查看更多
劳资没心,怎么记你
4楼-- · 2020-06-30 12:39

to add yet another solution

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");
    ...
}

or with 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) {

}
查看更多
登录 后发表回答