我正在编写一个网络库,并大量使用移动语义来处理文件描述符的所有权。我的一个类希望接收其他类型的文件描述符包装器并获得所有权,所以它类似于
struct OwnershipReceiver
{
template <typename T>
void receive_ownership(T&& t)
{
// taking file descriptor of t, and clear t
}
};
它必须处理多个不相关的类型,所以receive_ownership必须是一个模板,而且为了安全起见,我希望它只绑定到右值引用,这样用户在传递左值时就必须显式地声明std::move。
receive_ownership(std::move(some_lvalue));
但问题是: C++模板演绎允许不需要额外的努力就能传入一个左值。有一次,我无意中将一个左值传递给了receive_ownership,然后使用了这个左值(已清除),这实际上是在自找麻烦。
所以这里有一个问题:如何让模板只绑定到右值引用?
发布于 2011-10-23 08:51:05
您可以将T
限制为不是左值引用,从而阻止左值绑定到它:
#include <type_traits>
struct OwnershipReceiver
{
template <typename T,
class = typename std::enable_if
<
!std::is_lvalue_reference<T>::value
>::type
>
void receive_ownership(T&& t)
{
// taking file descriptor of t, and clear t
}
};
向T
添加某种限制,使其只接受文件描述符包装器也可能是一个好主意。
发布于 2016-10-03 17:07:52
一种简单的方法是提供一个接受左值引用的已删除成员:
template<typename T> void receive_ownership(T&) = delete;
对于左值参数,这将始终是一个更好的匹配。
如果你有一个带有多个参数的函数,所有这些参数都需要是右值,我们将需要几个被删除的函数。在这种情况下,我们可能更喜欢使用SFINAE来对任何左值参数隐藏函数。
一种方法是使用C++17和Concepts TS:
#include <type_traits>
template<typename T>
void receive_ownership(T&& t)
requires !std::is_lvalue_reference<T>::value
{
// taking file descriptor of t, and clear t
}
或
#include <type_traits>
void receive_ownership(auto&& t)
requires std::is_rvalue_reference<decltype(t)>::value
{
// taking file descriptor of t, and clear t
}
更进一步,您可以定义自己的新概念,如果您想要重用它,或者只是为了更清晰,这可能会很有用:
#include <type_traits>
template<typename T>
concept bool rvalue = std::is_rvalue_reference<T&&>::value;
void receive_ownership(rvalue&& t)
{
// taking file descriptor of t, and clear t
}
注意:在GCC 6.1中,您需要将-fconcepts
传递给编译器,因为它是C++17的扩展,而不是它的核心部分。
为了完整起见,下面是我的简单测试:
#include <utility>
int main()
{
int a = 0;
receive_ownership(a); // error
receive_ownership(std::move(a)); // okay
const int b = 0;
receive_ownership(b); // error
receive_ownership(std::move(b)); // allowed - but unwise
}
发布于 2011-10-23 20:13:40
我学到了一些似乎经常让人困惑的东西:使用SFINAE是可以的,但我不能使用:
std::is_rvalue_reference<T>::value
它能像我想的那样工作的唯一方法是
!std::is_lvalue_reference<T>::value
原因是:我需要我的函数来接收rvalue,而不是rvalue reference。有条件地使用std::is_rvalue_reference<T>::value
启用的函数将不会接收右值,而是接收右值引用。
https://stackoverflow.com/questions/7863603
复制相似问题