【问题标题】:C++ STL question related to insert iterators and overloaded operators与插入迭代器和重载运算符相关的 C++ STL 问题
【发布时间】:2010-04-21 18:23:08
【问题描述】:
#include <list>
#include <set>
#include <iterator>
#include <algorithm>

using namespace std;

class MyContainer {
public:
 string value;

    MyContainer& operator=(const string& s) {
        this->value = s;
        return *this;
    }
};

int main() 
{
    list<string> strings;
    strings.push_back("0");
    strings.push_back("1");
    strings.push_back("2");

    set<MyContainer> containers;
    copy(strings.begin(), strings.end(), inserter(containers, containers.end()));
}

前面的代码无法编译。在标准 C++ 方式中,错误输出很冗长且难以理解。关键部分似乎是这个……

/usr/include/c++/4.4/bits/stl_algobase.h:313:错误:'__result.std::insert_iterator::operator* 中的 'operator=' 不匹配 [with _Container = std::set, std::分配器 >]() = __first.std::_List_iterator::operator* [with _Tp = std::basic_string, std::allocator >]()'

...我解释说需要的赋值运算符没有定义。我查看了 insert_iterator 的源代码,并注意到它重载了赋值运算符。复制算法必须使用插入迭代器重载赋值运算符来完成它的工作(?)。

我猜是因为我的输入迭代器在一个字符串容器上,而我的输出迭代器在一个 MyContainers 容器上,所以重载的 insert_iterator 赋值运算符不能再工作了。

这是我最好的猜测,但我可能错了。

那么,为什么这不起作用,我该如何完成我想要做的事情?

【问题讨论】:

    标签: c++ stl


    【解决方案1】:

    使用构造函数会起作用(这比赋值更有意义):

    class MyContainer {
    public:
     string value;
    
        MyContainer(const string& s): value(s) {
        }
    };
    

    那么第二个问题是set也要求它的内容是可比较的。

    至于原因,insert_iterator 通过重载operator= 工作:

    insert_iterator<Container>& operator= (typename Container::const_reference value);
    

    如您所见,右边的值必须是容器的值类型,或者可以隐式转换为容器的值类型,这正是(非显式)构造函数可以实现的,而赋值运算符却没有。


    从技术上讲,您也可以通过提供合适的转换函数使其在不更改类的情况下工作(例如,如果您不想要非显式构造函数):

    MyContainer from_string(const std::string& s)
    {
        MyContainer m;
        m = s;    //or any other method how to turn a string into MyContainer
        return m;
    }
    

    可以和std::transform一起使用:

    transform(strings.begin(), strings.end(), inserter(containers, containers.end()), from_string);
    

    【讨论】:

    • std::set 需要operator&lt;()
    • 严格来说,它没有。这是一个附带问题,并在答案中简要提及。
    【解决方案2】:

    您需要添加:
    1. 接受字符串的构造函数(您正在尝试将字符串添加到可以包含 MyContainer 对象的容器中)。
    2. bool operator 例如:

    class MyContainer
    {
      public:
       MyContainer(const string& v):value(v){};
    };
    bool operator <(const MyContainer &c1, const MyContainer &c2)
    {
    return c1.value <c2.value;
    }
    

    【讨论】:

      【解决方案3】:

      问题是双重的:

      1. 您正在尝试填充一组 MyContainer 对象
      2. ...来自string 对象列表。

      copy() 算法尝试将每个string 对象转换为MyContainer 对象。在 C++ 中,要向类 MyContainer 添加从 string 类型到 MyContainer 类型的转换支持,您需要添加一个采用 string 类型参数的构造函数:

      struct MyContainer {
          MyContainer(const string& s) : value(s) { }
          bool operator<(const MyContainer& o) const { return value < o.value; }
      
      private:
          string s;
      };
      

      您不需要赋值运算符,因为编译器可以通过复制构造函数完成复制:将string 转换为MyContainer,然后使用默认赋值运算符分配一个MyContainer 对象到另一个。但是,您将需要一个 operator&lt;(),因为 C++ 集是已排序的。

      【讨论】:

        猜你喜欢
        • 2011-12-07
        • 1970-01-01
        • 2020-06-14
        • 2022-01-05
        • 2011-10-18
        • 2012-01-05
        • 2011-02-24
        • 2021-04-24
        • 1970-01-01
        相关资源
        最近更新 更多