2017-01-19 93 views
3

下面的代碼片段編譯時帶有一個非常重要的警告。綁定const std :: pair <T, U>&std :: pair的值<const T, U>

#include <map> 
#include <vector> 

template <typename iterator> 
const std::pair<int, float> &foo(iterator it) { 
    return *it; 
} 

int main() { 
    std::vector<std::pair<int, float>> vector; 
    std::map<int, float> map; 
    vector.push_back(std::make_pair(0, 0.0)); 
    map.insert(std::make_pair(0, 0.0)); 
    const std::pair<int, float> &r1 = foo(vector.begin()); 
    const std::pair<int, float> &r2 = foo(map.begin()); 
    if (r1 != r2) { 
    return 1; 
    } 
    return 0; 
} 

有從std::pair<const int, float>std::pair<int, float>期間foo(map.begin())創建的懸空參考的隱式轉換。

ref2.cpp: In instantiation of ‘const std::pair<int, float>& foo(iterator) [with iterator = std::_Rb_tree_iterator<std::pair<const int, float> >]’: 
ref2.cpp:16:52: required from here 
ref2.cpp:7:11: warning: returning reference to temporary [-Wreturn-local-addr] 
    return *it; 
      ^~ 

我們可以在這種情況下,調整的r2類型std::pair<const int, float>。儘管如此,在一般情況下,將兩個調用的結果分配給類型兼容引用foo()會很有用。例如,對foo()的調用可能會封裝在總是返回std::pair<int, float>&的另一個函數中。

是否可以對參考分配進行操作,以解決const修飾符未對齊的問題?

+0

你應該寫'0.0f',所以你不會轉換'雙'到一個'浮動'(或者將你的'浮動'換成'雙')。 –

+0

爲什麼不使用'auto'? –

+1

@KerrekSB函數返回引用是該規則的一個很大的例外。 – hvd

回答

2

編輯

真正的問題是有關使std::pair<K,V>工作,std::pair<const K,V>; vector<>map<>是紅鯡魚。 (特別是看到爲什麼在std::map<>關鍵const討論here

更好的示例代碼可能是:

#include <vector> 

template <typename iterator> 
const std::pair<const int, float>& bar(iterator it) 
{ 
    return *it; 
} 

int main() 
{ 
    const std::vector<std::pair<const int, float>> v1{ std::make_pair(0, 0.0f) }; 
    bar(v1.begin()); 

    const std::vector<std::pair<int, float>> v2{ std::make_pair(0, 0.0f) }; 
    bar(v2.begin()); 

    return 0; 
} 

根據你的意見,你真的什麼試圖弄清楚如何使std::map<>迭代器像std::vector<>一樣工作;在兩種情況下結果應該是std::pair<>,而不是std::pair<const int, ...>

因此,我寫了這個黑客;我敢肯定,它有問題,和/或可以改進:

const auto& remove_const(const std::pair<const int, float>& p) { 
    return reinterpret_cast<const std::pair<int, float>&>(p); // :-(
} 

template <typename iterator> 
const std::pair<int, float> &foo(iterator it) { 
    return remove_const(*it); 
} 
+2

您應該爲此使用迭代器特徵。 –

+0

我明白這個答案,但oriignal問題涉及統一返回類型而不管模板參數的可能性,而不是使返回類型參數相關。 – epl

+0

@epl也許你想更新你的示例代碼,以更清楚地表明? –

1

您可以更改:

template <typename iterator> 
const std::pair<int, float> &foo(iterator it) { 
    return *it; 
} 

到:

template <typename iterator> 
decltype(auto) foo(iterator it) { 
    return *it; 
} 

這需要C++ 14,留與c + + 11使用:

auto foo(iterator it) -> decltype(*it) { 
+0

不將返回類型設置爲'auto'只是簡單地將調用程序的類型不兼容分配給作業?即使'r1'和'r2'也是'auto',它們在比較時仍然會是不同的類型,需要轉換嗎? – epl

+1

不,它只是爲foo選擇正確的返回類型 - 現在它始終是'std :: pair &',但它應該是:std :: pair &'和std :: pair &' – marcinj

+0

也是嚴格的不是'auto',而是'decltype(auto)',如果你選擇'auto',那麼區別很重要,那麼引用將被刪除。 – marcinj

相關問題