3 votes

Attacher const std :: pair <T, U> à la valeur de std :: pair <const T, U>

Le extrait de code ci-dessous compile avec un avertissement très important.

#include 
#include 

template 
const std::pair &foo(iterator it) {
  return *it;
}

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

Il existe une conversion implicite de std::pair en std::pair pendant foo(map.begin()) qui crée une référence pendante.

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

Nous pourrions ajuster le type de r2 à std::pair dans ce cas. Néanmoins, il serait utile, dans le cas général, d'assigner les résultats des deux appels à foo() à des références compatibles en termes de type. Par exemple, l'appel à foo() pourrait être enveloppé dans une autre fonction qui renvoie toujours std::pair&.

Est-ce que l'assignation par référence peut être réalisée de manière à contourner la mauvaise alignement des modificateurs const?

2voto

Dan Points 3922

Modifier

La question concerne vraiment comment faire fonctionner std::pair avec std::pair; vector<> et map<> sont des leurres. (En particulier, voir la discussion ici sur pourquoi la clé dans std::map<> est const.)

Un meilleur exemple de code pourrait être:

#include 

template 
const std::pair& bar(iterator it)
{
    return *it;
}

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

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

    return 0;
}

D'après vos commentaires, ce que vous essayez vraiment de comprendre est comment faire en sorte que l'itérateur de std::map<> fonctionne comme celui de std::vector<>; le résultat devrait être une std::pair<> dans les deux cas, pas std::pair.

Avec cela, j'ai écrit ce hack; je suis sûr qu'il a des problèmes et/ou pourrait être amélioré:

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

template 
const std::pair &foo(iterator it) {
    return remove_const(*it);
}

1voto

marcin_j Points 12237

Vous pouvez changer:

template 
const std::pair &foo(iterator it) {
  return *it;
}

à:

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

cela nécessite c++14, pour rester avec c++11 utilisez:

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X