sti*_*ijn 2 c++ overloading c++11
考虑用于检查参数值等的"契约"函数:
template< class T >
const T& AssertNotEmpty( const T& val )
{
//raise hell if val empty/0/...
return val;
}
Run Code Online (Sandbox Code Playgroud)
例如,可以使用如下:
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)
Run Code Online (Sandbox Code Playgroud)
现在进入C++ 11,我们希望Bar98按值获取构造函数参数并从中移出:
class Bar11
{
public:
Bar11( std::shared_ptr< int > val ) :
myVal( AssertNotEmpty( std::move( val ) ) )
{}
private:
std::shared_ptr< int > myVal;
};
Run Code Online (Sandbox Code Playgroud)
为了工作,AssertNotEmpty需要重写,我相当天真地认为通过使用通用引用可以工作:
template< class T >
T&& AssertNotEmpty( T&& val )
{
//...
return std::move( val );
}
Run Code Online (Sandbox Code Playgroud)
除了VS给出的最后一个(1)之外的所有情况似乎都没问题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&,如果我错了,请纠正我.
为了解决这个问题,我添加了通用引用作为重载,仅对非左值引用启用,以便在遇到像(1)中的普通左值引用时强制编译器选择const引用:
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 );
}
Run Code Online (Sandbox Code Playgroud)
似乎按预期工作,编译器在我尝试过的所有情况下都选择了正确的,但这是解决这个问题的'正确'的C++ 11方法吗?有任何可能的陷阱吗?是不是有一个不需要重复的解决方案?
我不认为你应该从该功能返回任何东西.但是,这可能会做你想要的.
template<class T>
auto AssertNotEmpty(T&& val) -> decltype(std::forward<T>(val))
{
//...
return std::forward<T>(val);
}
Run Code Online (Sandbox Code Playgroud)