Bind const std::pair<T, U>& to value of std::pair<const T, U>

北城以北 提交于 2019-12-22 09:41:40

问题


The below code snippet compiles with a very important warning.

#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;
}

There is an implicit conversion from std::pair<const int, float> to std::pair<int, float> during foo(map.begin()) that creates a dangling reference.

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;
           ^~

We could adjust the type of r2 to std::pair<const int, float> in this case. Nevertheless, it would be useful, in the general case, to assign the results of the two calls to foo() to type-compatible references. For example, the call to foo() might be wrapped in another function that always returns std::pair<int, float>&.

Can the reference assignment be made to operatate in a way that works around the misalignment of const modifiers?


回答1:


Edit

The question is really about making std::pair<K,V> work with std::pair<const K,V>; vector<> and map<> are red-herrings. (In particular, see the discussion here about why the key in std::map<> is const.)

Better sample code might be:

#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;
}

According to your comments, what you're really trying to figure out is how to make the std::map<> iterator work like std::vector<>; the result should be a std::pair<> in both cases, not std::pair<const int, ...>.

With that, I've written this hack; I'm sure it's got problems and/or could be improved:

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:


You might change:

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

to:

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

this requires c++14, to stay with c++11 use:

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


来源:https://stackoverflow.com/questions/41752812/bind-const-stdpairt-u-to-value-of-stdpairconst-t-u

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!