函数模板仅采用右值

问题描述 投票:0回答:3

编写仅采用左值的函数很容易

template <typename T>
void f(T&);

但是由于通用引用,编写只接受右值引用的引用并不简单。 有没有办法编写只接受右值引用的通用函数? (返回类型并不是真正的问题)

template <typename T>
void only_rvals(T&&);

哪里

int i{};
only_rvals(i); // fails to compile
only_rvals(6); // successfully compiles
c++ templates c++11 rvalue-reference
3个回答
11
投票

添加一个

template<class T>
void only_rvals(T&)=delete;

超载到通用的。 它将是首选,如果选择则会生成错误。

或者,SFINAE 检查,或后 C++1y 要求子句,或

static_assert
,或使用
is_reference
或类似的标签调度都可以工作。

理想情况下,您希望调用时出现故障、代码清晰、诊断清晰、解决方案稳健且可扩展。 后 C++1y 的要求最终将是最好的。

static_assert
提供了清晰的诊断(与标记调度一样,但您希望将名为
is_rvalue
的特征分派到
true_type
),并且 SFINAE 和
=delete
使错误发生在调用站点。
=delete
无法扩展到更多参数,SFINAE 很脆弱。

SFINAE 和

requires
允许使用替代重载。 这可能是所希望的,也可能不是。


4
投票

我可以看到两种可能的解决方案。 第一个使用

static_assert
在编译时检查推导的类型是否是左值引用。 如果是,则编译会在该行失败,并出现您想要添加的任何有意义的错误

template <typename T>
void only_rvals(T&& t) {
    static_assert(!std::is_lvalue_reference<T>::value,
            "I only work with rvalues");
    // ...
}

如果您希望编译器“自然”失败并出现(imo)难以理解的错误,您可以使用辅助函数(此处使用

_impl
)来实现。 被调用函数使用
remove_reference
来调用其模板参数具有非引用类型的辅助函数。 这确保实例化的帮助器具有其参数类型的右值引用。 如果原始类型是左值引用,则调用将失败,因为尝试将参数作为左值引用转发。

#include <type_traits>
#include <utility>

template <typename T>
void only_rvals_impl(T&& t) {
    //...
}

template <typename T>
void only_rvals(T&& t) {
    // no type deduction on this call, explicit instantiation
    only_rvals_impl<typename std::remove_reference<T>::type>(
            std::forward<T>(t));
}

@dyp 评论中使用 SFINAE 的第三个解决方案

template<typename T>
typename std::enable_if< !std::is_lvalue_reference<T>{}, void>::type
only_rvals(T&& t)  {
    //...
}

void
中的
enable_if
是不必要的,因为它是默认值,但此处显示是为了易于修改的解决方案


0
投票
  1. 如果 P 是对 cv-unqualified
  2. 的右值引用

记下此要求和标准中的示例代码。 您所需要的只是“假”const/volatile T&&

template <typename T>
void only_rvals(volatile T&&);
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.