【问题标题】:access key in constructor of struct in a map地图中结构的构造函数中的访问键
【发布时间】:2016-10-13 14:46:13
【问题描述】:

用例:记录缓冲区。这是基本的想法。 使其工作需要记录结构的构造函数知道在将元素添加到映射时用作记录编号的键。 当然,这可以用更多的代码来完成,但这对我来说看起来最优雅。 最少编码:

#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:上面的代码不起作用。 任何想法如何让它发挥作用? 编辑2: 我派生了一个 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);
    }
};

这确实有效。我仍然对 cme​​ts 向我指出我以不必要的复杂等方式这样做很感兴趣。我有吗?可以少花些功夫吗?

【问题讨论】:

  • 那么您的问题到底是什么?它甚至可以在没有默认构造函数的情况下工作吗?

标签: c++ dictionary


【解决方案1】:

因此,您希望使用 record(unsigned) 构造函数而不是默认构造函数来构造 record 对象。

很遗憾,operator[] (reference) 无法做到这一点:

如果 k 匹配容器中某个元素的键,则函数 返回对其映射值的引用。

如果 k 不匹配容器中任何元素的键,则 函数使用该键插入一个新元素并返回一个引用 到它的映射值。请注意,这总是会增加容器 大小加一,即使没有为元素分配映射值( 元素是使用其默认构造函数构造的)。

我不建议为std::map 重载operator[],对我来说这似乎是一个糟糕的设计。

但是,您可以使用其他方法来执行此操作,例如 insertemplace (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;
}

【讨论】:

  • 感谢您指出之前的讨论。它很有用 - 并且有一个建议可以做我所做的事情,以及对 boost 的引用,这将是有用的。我会看看我是否可以通过使其更具体来“解决”“糟糕的设计”问题,例如仅限整数键。 Imo 这对于想要一个还允许方括号引用的解决方案来说已经足够基本了。
  • @Jan,请注意,其他程序员可能会对您的程序/库中的非标准 STL 容器语义感到惊讶,这违反了en.wikipedia.org/wiki/Principle_of_least_astonishment。我不是在评判什么,只是陈述我的个人意见:)
猜你喜欢
  • 2010-11-10
  • 1970-01-01
  • 2023-04-02
  • 2013-05-07
  • 2023-03-18
  • 1970-01-01
  • 2012-02-27
  • 2012-07-06
  • 2014-02-23
相关资源
最近更新 更多