2014-11-04 69 views
2

我想要一個具有具體類型的通用引用參數的函數。我希望它是通用引用,所以當我不想檢查存儲在其中的值時,我可以傳遞一個臨時對象。具體類型的通用引用

這裏是例子:

bool bCompareData(const uint8_t *arg_0, const uint8_t *arg_1, size_t &szComparedData) 
{ 
    size_t &i = szComparedData; 

    for (; arg_1[i]; ++i) 
     if (arg_1[i] != arg_0[i]) 
      return false; 

    return true; 
} 

和可能的函數調用:

bCompareData(Obj.uIdObject.data(), Ref.uIdTargetObject.data(), size_t()) // here we are passing a temporary (rvalue) 
/*________________________*/ 
size_t lval; 
bCompareData(Obj.uIdObject.data(), Ref.uIdTargetObject.data(), lval) // here we are passing a named variable (lvalue) 

使用在第一個函數調用編譯器上面的函數聲明會給出一個錯誤,如果我改變「爲size_t & szComparedData「to rvalue reference」size_t & & szComparedData「它會在第二次調用失敗。

現在我需要的是通用引用,但我也想在我的參數上使用具體類型,而不是使用模板。

我使用VC++ U3 2013編譯器。

+1

MSVC是否允許第一個呢? (將非const引用綁定到臨時) – 2014-11-04 19:08:24

+0

您似乎希望最後一個參數是可選的。爲什麼不簡單地提供一個沒有這個參數的重載,並用一個本地的虛擬參數調用另一個版本? – 2014-11-04 19:09:07

+0

@FrançoisMoisan:傳遞一個臨時丟棄結果,所以可選的有意義,但通過一個臨時也允許不同的起點。我不確定可選參數是否真的是他想要的。 – 2014-11-04 19:11:07

回答

5

通用引用僅適用於模板和定義類型推導。您只能使用SFINAE限制引用特定類型:

template< typename S > 
typename std::enable_if< 
    std::is_same<typename std::decay<S>::type,size_t>::value, 
bool>::type 
bCompareData(const uint8_t *arg_0, const uint8_t *arg_1, S&& szComparedData) 
{ 
    // ... 
} 

,或者你需要重載你的方法,如果你真的需要避免模板:

bool bCompareData(const uint8_t *arg_0, const uint8_t *arg_1, size_t& szComparedData) 
{ 
    // ... 
} 

bool bCompareData(const uint8_t *arg_0, const uint8_t *arg_1, size_t&& szComparedData) 
{ 
    // ... 
} 
+0

該函數修改輸入,所以匹配'const size_t'變量將是一個錯誤。 (此外,我認爲你的重載會造成歧義) – 2014-11-04 19:08:31

+0

你的超載版本不起作用,因爲函數修改左值 – 2014-11-04 19:10:07

+0

@MooingDuck是的,但是'A&'和'A &&'毫不含糊,適用於所有情況?但也許在這裏沒問題,因爲問題確實將其限制爲可修改值或臨時值,不包括常量值。不尋常但可能。 – 2014-11-04 19:10:28

2

燦」 t有一個通用的引用而不是使用模板,因爲「通用引用」是模板的事情。你想要的是能夠傳遞一個左值或右值,這可以在沒有模板的情況下完成。

這裏的正確工具是重載。而有趣的是,這隻需要一個非常簡單的重載。

bool bCompareData(const uint8_t *arg_0, const uint8_t *arg_1, size_t &szComparedData) 
{ 
    size_t &i = szComparedData; 

    for (; arg_1[i]; ++i) 
     if (arg_1[i] != arg_0[i]) 
      return false; 

    return true; 
} 
bool bCompareData(const uint8_t *arg_0, const uint8_t *arg_1, size_t &&szComparedData) 
{ return bCompareData(arg_0, arg_1, szComparedData);} 

這工作,因爲&&在函數參數列表告訴這個函數的參數是構建從一個右值,但所有的命名值本身是左值。既然它有名字,它是一個左值,你可以簡單地將它傳遞給現有的函數。

+0

既不會匹配'const size_t'變量 – 2014-11-04 19:06:31

+0

@PiotrS .:該函數修改輸入,所以匹配'const size_t'變量將是一個錯誤。 – 2014-11-04 19:07:03

0

或者我做了什麼之後,我相信這是不是最好的解決辦法:

template <typename T = size_t> 

inline bool bCompareData(const uint8_t *arg_0, const uint8_t *arg_1, T &&arg_2 = size_t()) 
{ 
    arg_2 = 0; 

    extern bool _bCompareData(const uint8_t *, const uint8_t *, size_t &); //compare data 

    return _bCompareData(arg_0, arg_1, arg_2); 
} 

C++是一種很奇怪的語言。我的意思是'左值'&'左值'引用具有相同的大小和屬性,所以它們是如何變成不同類型的。

+0

它不需要模板,但這是解決問題的一種方法。 – 2014-11-04 19:11:54

+0

左值和右值不具有相同的屬性。例如,右值不能被賦值,或者被可變引用傳遞。 'char [12]'和'std :: vector '有時可能具有相同的大小,但很難將它們稱爲同一類型。 – 2014-11-04 19:14:58