2017-01-19 16 views
3

Этот фрагмент кода компилируется с очень важным предупреждением.Bind const std :: pair <T, U> & to value of 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>&.

Может ли задание ссылки выполняться таким образом, чтобы он работал вокруг смещения константных модификаторов?

+0

вы должны написать '0.0f', чтобы вы не конвертировали' double' в 'float' (или изменить' 'float' '' '' '' '' '' '' '' '' '' '' ''. –

+0

Почему бы просто не использовать 'auto'? –

+1

@KerrekSB Функции, возвращающие ссылки, являются большим исключением из этого правила. – hvd

ответ

2

Редактировать

вопрос действительно о том, чтобы std::pair<K,V> работу с std::pair<const K,V>; vector<> и map<> - красные сельди. (В частности, смотрите обсуждение here о том, почему в std::map<>ключ является const.)

Лучше пример кода может быть:

#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