2015-10-09 2 views
1
struct MapInserter 
{ 
private: 
    int count; 

public: 
    explicit MapInserter() 
     : count(0) 
    { 
    } 

    std::pair<int, std::string> operator()(std::string& value) 
    { 
     return std::make_pair(count++, value); 
    } 
}; 

vector<std::string> words = { "one", "two", "three","four","five" }; 
std::map<int, std::string> map; 
MapInserter inserter; 
transform(words.begin(), words.end(), map.begin(), inserter); 

for (auto it = map.begin(), end = map.end(); it != end; ++it) 
    cout << it->first << " : " << it->second << endl; 

return 0; 

это код. VS возвращает ошибку компиляции в отношении l-value specifies const object.l-value указывает объект const при использовании std :: make_pair

Щелчок по ошибке перемещает вас на следующий код в файл с именем утилита

template<class _Other1, 
    class _Other2> 
    _Myt& operator=(pair<_Other1, _Other2>&& _Right) 
    { // assign from moved compatible pair 
    first = _STD forward<_Other1>(_Right.first); 
    second = _STD forward<_Other2>(_Right.second); 
    return (*this); 
    } 

на первом, я имел operator() взять const std::string& так что я удалил Конст, потому что это, очевидно, идет о функции make_pair , Но это все еще не исчезло. Может ли кто-нибудь указать мне на эту ошибку?

+1

Почему вы берете 'значение' ссылкой на lvalue? Просто возьмите по значению и переместите или возьмите по ссылке на 'const'. Я просто быстро просмотрел код, но думаю, что это может решить проблему. –

+0

Я не уверен, как выразить это формально, но я подозреваю, что это зависает на 'count ++', и было бы лучше, если бы вы перенесли инкремент из вызова в std :: make_pair(). – Logicrat

+0

'std :: pair operator() (std :: string value) {return std :: make_pair (count ++, value); } 'все еще давая ошибку –

ответ

6

Проблема в том, что std::transform() попытается установить назначить существующим элементам целевого контейнера. Ключи карты являются постоянными и не могут быть назначены, поэтому вы получаете ошибку компилятора. Но даже если бы они были, вы бы получили неопределенное поведение во время выполнения здесь, потому что целевой контейнер пуст, и std::transform() ожидал, что он будет содержать столько элементов, сколько диапазон ввода.

Вы должны использовать std::inserter() создать INSERTER итератор, например, так:

vector<std::string> words = { "one", "two", "three","four","five" }; 
std::map<int, std::string> map; 
MapInserter inserter; 
transform(words.begin(), words.end(), std::inserter(map, map.begin()), inserter); 
//         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 

Вот live example.

Кроме того, принимая value строки на изменяемой ссылке Lvalue в операторе вызова вашего MapInserter не очень хорошая идея: вы не хотите, чтобы аргумент должны быть изменен, так что вы должны либо взять его const& или - мой совет - принять его по значению, а затем переместить его в возвращаемых пары, например, так:

std::pair<int, std::string> operator()(std::string value) 
{ 
    return {count++, std::move(value)}; 
} 

с std::pair «s конструктора не explicit, вам даже не нужен вызов std::make_pair() в этом случае.

+0

Yup. работал как шарм. только пришлось удалить строку '' из 'make_pair' @thab, предложенную и возвращенную ей в' const & ' –

+0

. Я знаю об объектах const ref. Из моей тренировки на C++ я привык только принимать by-val, если мне это абсолютно необходимо. –

+0

@GioraGuttsait: На самом деле, как я писал в последнем отредактировании ответа, вам даже не нужно 'make_pair()'. Вы можете просто использовать инициализацию списка скобок. –