写一个只占左值的函数很容易
template <typename T>
void f(T&);
但由于universal references,写一个只接受右值引用的方法并不是直接的。有没有办法编写一个只接受rvalue refs的泛型函数? (返回类型不是真正的问题)
template <typename T>
void only_rvals(T&&);
,其中
int i{};
only_rvals(i); // fails to compile
only_rvals(6); // successfully compiles
答案 0 :(得分:9)
添加
template<class T>
void only_rvals(T&)=delete;
普遍的过载。它将是首选,并在选择时生成错误。
或者,SFINAE检查,或后C ++ 1y要求条款,static_assert
或使用is_reference
或类似的标签发送都可以。
理想情况下,您希望在通话点失败,代码清晰,诊断清晰,解决方案的稳健性和可扩展性。后C ++ 1y要求最终将是最好的。 static_assert
提供了明确的诊断(可以标记为disptching,但您希望调度is_rvalue
的特性发送到true_type
),SFINAE和=delete
会在调用时发生错误现场。 =delete
不能扩展到更多参数,SFINAE很脆弱。
SFINAE和requires
允许使用替代重载。这可能是也可能不是。
答案 1 :(得分: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
是不必要的,因为它是默认设置,但此处显示的是易于修改的解决方案