2017-01-19 64 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

相关问题