【问题标题】:How to force a function to only accept an lvalue reference parameter如何强制函数只接受左值引用参数
【发布时间】:2018-06-14 08:01:17
【问题描述】:

这是我的情况:

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&amp;&amp; f 只接受非const 左值引用。我应该如何执行?

【问题讨论】:

标签: c++ templates


【解决方案1】:

我想确保模板参数 F&& f 只接受非常量左值引用。

那么您不应该使用转发引用。转发的整个想法是接受任何值类别并将其保留以供将来调用。所以第一个解决方法是不要在这里使用错误的技术,而是通过左值引用来接受:

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

如果您尝试将右值传递给函数,那应该会让编译器很好地抱怨。它不会阻止编译器允许 const 左值(F 将被推断为const F1)。如果你真的想防止这种情况,你可以添加另一个重载:

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

F const&amp; 的参数类型将更好地匹配 const 左值(以及右值,顺便说一句),所以这个会在重载决议中被选中,并立即导致错误,因为它的定义被删除。非常量左值将被路由到您要定义的函数。

【讨论】:

  • 我喜欢这个。声明非常明确:你可以接受所有这些东西 ... 除了这些。如果您尝试不正确地使用模板,您可能还会收到更好的错误消息。在这里使用static_assert 感觉有点hacky,但也许这就是我。
  • @PaulSanders - 所有方法都有利有弊。我喜欢 Joseph 的解决方案的地方在于它们是本地化的(自定义消息很好,概念解决方案也很清晰 IMO)。我的思绪跳到超载,因为这就是我习惯于搞砸这些事情的方式。但这对你来说就是这样,每个人通常都有很棒的建议。
  • 是的,好吧,我猜它只是我,我对这一切都很陌生。那时也为约瑟夫+1,我仔细看了看,我同意你的看法。 [警告:哲学警告] 玩具箱里的玩具太多了,差不多。新手(在大多数方面也包括我)可以将自己与所有这些东西打成最奇妙的结。 [呃,定义“东西”]。
  • @PaulSanders - 就 C++ 而言,我认为自己也是新手。我总是在学习一些新的东西。 SO上的某个人会一次又一次地为我认为不可能彻底解决的问题发布一个优雅的解决方案。 Here's one for you。它利用了最棘手的解析本身。
  • 是的,边缘天才。我自己会使用脚本,面对这个问题,那将是我的极限。我看到它给你留下了深刻的印象 - 难怪。
【解决方案2】:

您可以通过左值引用获取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> {
    …
}

【讨论】:

  • 有人生活在未来;)
【解决方案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) {

}

【讨论】:

    猜你喜欢
    • 2013-07-12
    • 2012-03-09
    • 2015-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-26
    • 1970-01-01
    相关资源
    最近更新 更多