考慮用於檢查的參數等值的「契約」功能:是否需要重載const和通用引用?
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解決方法嗎?有沒有可能的陷阱?沒有不需要重複的解決方案嗎?
什麼是PassMe? –
'AssertNotEmpty'沒有協議修改它的值,也沒有返回任何東西,至少不是這個名字... –
你想'std :: forward',而不是'std :: move'。 –