2013-01-09 26 views
2

考慮用於檢查的參數等值的「契約」功能:是否需要重載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解決方法嗎?有沒有可能的陷阱?沒有不需要重複的解決方案嗎?

+0

什麼是PassMe? –

+2

'AssertNotEmpty'沒有協議修改它的值,也沒有返回任何東西,至少不是這個名字... –

+4

你想'std :: forward ',而不是'std :: move'。 –

回答

3

這不是嚴格意義上的回答你的問題,但我不認爲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 ...

+0

有趣的使用逗號運算符,並不知道你可以這樣做。 – ronag

+0

你說得對,函數不應該修改也不會返回任何東西,它唯一的原因就是能夠使用一個襯墊。但是,您的逗號運算符解決方案是解決該問題的一個非常好的方法! – stijn

5

我不認爲你應該從該函數返回任何東西。但是,這可能會做你想要的。

template<class T> 
auto AssertNotEmpty(T&& val) -> decltype(std::forward<T>(val)) 
{ 
    //... 
    return std::forward<T>(val); 
} 
+1

'decltype(std :: forward (val))'是一個比較詳細的說'T &&'的方式。 –

+0

@ R.MartinhoFernandes:不知道它是否總是會導致一個'T &&',所以我採取了安全的選擇。 – ronag

+0

你能詳細說明爲什麼向前確定,但移動不是? – stijn

相關問題