是否需要为const和通用引用重载?
Are overloads for const and universal references necessary?
考虑一个用于检查参数值等的"契约"函数:
template< class T >
const T& AssertNotEmpty( const T& val )
{
//raise hell if val empty/0/...
return val;
}
例如可以这样使用:
void foo( const std::shared_ptr< int >& val )
{
AssertNotEmpty( val );
//use *val
}
class Bar98
{
public:
Bar98( const std::shared_ptr< int >& val ) : myVal( AssertNotEmpty( val ) ) {}
private:
std::shared_ptr< int > myVal;
};
std::shared_ptr< int > x;
//...
AssertNotEmpty( x ); //(1)
现在进入c++ 11,我们希望Bar98按值获取构造函数参数并从中移动:
class Bar11
{
public:
Bar11( std::shared_ptr< int > val ) :
myVal( AssertNotEmpty( std::move( val ) ) )
{}
private:
std::shared_ptr< int > myVal;
};
要使这个工作AssertNotEmpty需要重写,我相当天真地认为通过使用通用引用可以工作:
template< class T >
T&& AssertNotEmpty( T&& val )
{
//...
return std::move( val );
}
这似乎对所有情况都很好,除了最后一个(1),其中VS给出warning C4239: nonstandard extension used : 'return' : conversion from 'std::shared_ptr<int>' to 'std::shared_ptr<int> &'
。据我所知,这是因为编译器看到AssertNotEmpty( x )
是AssertNotEmpty( T& && x )
,它崩溃成AssertNotEmpty( T& )
,你不能从T&
移动,如果我错了,请纠正我。
为了解决这个问题,我添加了通用引用作为重载,仅对非左值引用启用,以强制编译器在遇到普通左值引用时也选择const引用,如(1):
template< class T >
const T& AssertNotEmpty( const T& val )
{
//...
return val;
}
template< class T >
T&& AssertNotEmpty( T&& val, typename std::enable_if< !std::is_lvalue_reference< T >::value, int >::type* = 0 )
{
//...
return std::move( val );
}
似乎按预期工作,编译器在我尝试的所有情况下选择正确的一个,但这是"正确的"c++ 11解决这个问题的方法吗?有什么可能的陷阱吗?难道没有不需要复制的解决方案吗?
我不认为你应该从那个函数返回任何东西。然而,这可能会达到您的目的。
template<class T>
auto AssertNotEmpty(T&& val) -> decltype(std::forward<T>(val))
{
//...
return std::forward<T>(val);
}
这不是严格回答你的问题,但我不认为AssertNotEmpty
应该修改它的参数也不返回任何东西。由于逗号操作符,您仍然可以在构造函数中使用它,例如:
template< class T >
void AssertNotEmpty( T const& val )
{
/* assert( val not empty ) */
}
class Bar11
{
public:
Bar11( std::shared_ptr< int > val ) :
myVal( ( AssertNotEmpty( val ), std::move( val ) ) )
{}
private:
std::shared_ptr< int > myVal;
};
注意,额外的括号是必需的,所以两个表达式求值,结果是最后一个表达式的结果。
否则,应该重命名函数。我想到了AssertNotEmptyThenMove
之类的东西
- 取消引用运算符不能重载
- 错误:无法解析对重载函数的引用;你的意思是调用它吗?
- 传递空初始值设定项列表时使用右值和左值引用候选项的重载解析
- 为什么我的运算符 + 重载尽管是通过引用传递的,但仍调用我的复制构造函数?
- C++编程:运算符重载中的引用如何工作?
- 重载运算符*以获取对另一个类的实例的引用
- 对运算符=使用通用引用,而不是多个重载
- 如何重载下标运算符 [] 以引用 2d STL 数组?
- 具有参数包和通用引用的重载选择
- 有什么理由用右值引用重载运算符吗?
- 封装 ublas 并将常量引用重载到 operator()
- std::forward() 的右值引用重载的目的是什么?
- std::move into static_pointer_cast:为什么static_pointer_cast没有右值引用重载?
- 通过引用重载多个函数对象
- C++ 右值引用重载,而不是移动构造函数
- 通过引用重载运算符-C++来传递对象
- 指针和引用 + 重载运算符
- 当基类型为函数引用时,右值引用重载
- 在没有歧义的情况下,是否允许通过引用重载函数
- 是否需要为const和通用引用重载?