简体   繁体   English

访问地图中struct的构造函数中的键

[英]access key in constructor of struct in a map

Use case: a buffer of records. 用例:记录缓冲区。 Here is the basic idea. 这是基本的想法。 Making it work requires that the constructor of the record struct knows the key, which is used as recordnumber, when an element is added to the map. 使其工作要求当元素添加到地图时,记录结构的构造函数知道用作记录编号的键。 Of course, this can be done with more code, but this looks most elegant to me. 当然,这可以通过更多代码完成,但这对我来说看起来最优雅。 Minimally coded: 最小编码:

#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: code above will not work. Edit1:上面的代码不起作用。 Any ideas how to get this to work? 任何想法如何让这个工作? Edit2: I derived a mapplus class adding another map::operator[]: Edit2:我派生了一个mapplus类,添加了另一个map :: operator []:

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

This does work. 这确实有效。 I am still interested in comments pointing out to me that I did this in a needlessly complex etc. way. 我仍然对向我指出的评论感兴趣,我以不必要的复杂等方式做到了这一点。 Did I? 我有吗? Can it be done with less ado? 可以用更少的ado来完成吗?

So, you want record objects to be constructed using your record(unsigned) constructor, rather than the default constructor. 因此,您希望使用record(unsigned)构造函数而不是默认构造函数构造record对象。

Unfortunately, there's no way to do this with operator[] ( reference ): 不幸的是,没有办法用operator[]参考 )做到这一点:

If k matches the key of an element in the container, the function returns a reference to its mapped value. 如果k匹配容器中元素的键,则该函数返回对其映射值的引用。

If k does not match the key of any element in the container, the function inserts a new element with that key and returns a reference to its mapped value. 如果k与容器中任何元素的键不匹配,则该函数将使用该键插入一个新元素,并返回对其映射值的引用。 Notice that this always increases the container size by one, even if no mapped value is assigned to the element (the element is constructed using its default constructor). 请注意,即使没有为元素指定映射值(使用其默认构造函数构造元素),这也会将容器大小增加1。

I would not recommend overloading operator[] for std::map , for me it seems like a bad design. 我不建议为std::map重载operator[] ,对我来说这似乎是一个糟糕的设计。

However, you can do it with other methods, like insert or emplace (C++11). 但是,您可以使用其他方法来完成,例如insertemplace (C ++ 11)。 See, for example, this answer: Using std::map<K,V> where V has no usable default constructor 例如,请参阅以下答案: 使用std :: map <K,V>其中V没有可用的默认构造函数

Tested example: 经过测试的例子:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM