2016-06-13 4 views
1

Использование: буфер записей. Вот основная идея. Выполнение этой работы требует, чтобы конструктор структуры записи знал ключ, который используется как номер записи, когда элемент добавляется к карте. Конечно, это может быть сделано с большим количеством кода, но это выглядит очень элегантно для меня. Минимально закодированы:ключ доступа в конструкторе структуры на карте

#include <whatever> 
struct record 
{ 
    string foo; 
    record(unsigned irec) { foo=readrecord(irec); } 
}; 

map<unsigned,record>recbuf; 

int main() 
{ 
    // if the element is not yet in the map, it should be read. 
    string foo_ten=recbuf[10].foo; 
    // do something with the result 
    printf("foo_ten: %s\n",foo_ten.c_str()); 
    return 0; 
} 

Edit1: Код выше не будет работать. Любые идеи, как заставить это работать? Edit2: Я вывел класс mapplus добавив еще одну карту :: оператор []:

template<class _Kty, class _Ty, class _Pr = less<_Kty>, class _Alloc = allocator<pair<const _Kty, _Ty> > >class mapplus :public map<_Kty, _Ty, _Pr, _Alloc> 
{ 
public: 
    mapped_type& operator[](const _Kty &_Keyval) 
    { // find element matching _Keyval or insert with default mapped 
     iterator _Where = _Mybase::lower_bound(_Keyval); 
     if (_Where == _Mybase::end() 
      || _Mybase::_Getcomp()(_Keyval, _Mybase::_Key(_Where._Mynode()))) 

      _Where = _Mybase::emplace_hint(_Where, 
       _Keyval, 
       _Ty(_Keyval)); 
     return (_Where->second); 
    } 
}; 

Это делает работу. Меня все еще интересуют комментарии, указывающие на то, что я делал это без лишних сложностей и т. Д. Я? Можно ли это сделать с меньшим количеством суматохи?

+1

Так что именно ваш вопрос? Он работает даже без конструктора по умолчанию? –

ответ

0

Итак, вы хотите, чтобы объекты record были построены с использованием вашего конструктора record(unsigned), а не конструктора по умолчанию.

К сожалению, нет никакого способа, чтобы сделать это с помощью operator[] (reference):

Если к соответствует ключу элемента в контейнере, функция возвращает ссылку на его отображенное значение.

Если k не соответствует ключу любого элемента в контейнере, функция вставляет новый элемент с этим ключом и возвращает ссылку на ее отображаемое значение. Обратите внимание, что это всегда увеличивает размер контейнера , даже если для элемента не присвоено сопоставленное значение (элемент построен с использованием его конструктора по умолчанию).

я бы не рекомендовал перегрузки operator[] для std::map, мне кажется, что плохой дизайн.

Однако вы можете сделать это другими способами, например insert или emplace (C++ 11). См, например, этот ответ: Using std::map<K,V> where V has no usable default constructor

Испытано пример:

#include <map> 
#include <sstream> 
#include <iostream> 


std::string readRecord(int id) 
{ 
    std::stringstream stream; 
    stream << id; 
    return stream.str(); 
} 

struct Record 
{ 
    Record(int id) 
     : foo(readRecord(id)) 
    { 
    } 

    std::string foo; 
}; 

int main() 
{ 
    std::map<int, Record> m; 
    for (int i = 0; i < 10; ++i) 
     m.insert(std::make_pair(i, Record(i))); 

    std::cout << m.at(5).foo << std::endl; 
    // std::cout << m[7].foo << std::endl; // error 'Record::Record': no appropriate default constructor available 

    return 0; 
} 
+0

Спасибо за указание на более раннее обсуждение. Это полезно - и есть предложение сделать то, что я сделал, и ссылки на boost, которые будут полезны. Я посмотрю, смогу ли я «решить» проблему «плохого дизайна», сделав ее более конкретным, например. только целые ключи. Imo это достаточно основательно, чтобы хотеть решение, которое также позволяет использовать квадратную скобку. – Jan

+0

@Jan, просто имейте в виду, что другие программисты могут быть удивлены нестандартной семантикой контейнера STL в вашей программе/библиотеке, что нарушает https://en.wikipedia.org/wiki/Principle_of_least_astonishment. Я не сужу или ничего, просто укажите свое личное мнение :) –

Смежные вопросы