自定义类型使用STL关联容器

上次总结STL容器时有提到,我们不能直接把自定义类型作为关联容器set或map的key。C++编译器会报错的。

如果想这样做,需要对自定义类型规定一个< 运算符。

  • 方法1:在自定义类型内定义<运算符。

源代码示例如文章最后。需要注意以下几点。

  • bool operator< (const Test_Data & cmp) const 中,参数类型必须是const引用,且函数也得是const函数,否则会报错。

定义了operator<函数后,std::set<Test_Data>和std::map<Test_Data , unsigned int > 可正常使用。std::set<Test_Data> 等同于 std::set<Test_Data, std::less< Test_Data > >

/usr/include/c++/5/bits/stl_function.h:387:20: error: no match for  operator< (operand types are const Test_Data and const Test_Data)
       { return __x < __y; }

  • Test_Data的唯一一个显式构造函数带参,如果有不带默认值的参数,则Test_Data没有了默认构造函数,这时候,使用Test_Data作为map的value type将会报错。

/usr/include/c++/5/tuple:1172:70: error: no matching function for call to Test_Data::Test_Data()
         second(std::forward<_Args2>(std::get<_Indexes2>(__tuple2))...)

  • 对于std::map<Test_Data*, unsigned int >,因为Test_Data*是一个指针,而指针是一个C/C++ 内置type,故即使没有定义operator<,也可以正常使用。
  • 对于std::set<Test_Data>::iterator it,由于*it的返回值是const (参考《C++ Primer 第5版》P382页,set的关键字是只读的,不可修改),故如果operator<< (std::ostream &os , Test_Data & data) 不加const,会报错。
  • 一般来说,const修饰的变量是安全的,没有const修饰的变量是不安全的,一般在传参的时候,非const修饰的的变量可以传给const修饰的,而const 修饰的不可以传给非const修饰的形参,这就相当于把安全的东西交给了不安全的人;而赋值的话更不用说了,const修饰的不可以传给没有const修饰的变量

 error: binding const Test_Data to reference of type Test_Data& discards qualifiers
   cout<<"["<<i<<"] data "<< *it <<endl

代码中给出了两种operator<的实现,对应的执行结果分别为

  

 

  • 方法二:

定义一个比较操作符,使用它作为set或map的模板参数,在定义set或map的时候,需要把classcomp 当做参数传进去std::set<Test_Data, classcomp >。

  • 方法三

使用函数指针,需要注意的是函数指针的使用,C++11增加了decltype关键字,在使用函数指针时更加方便,但需要在编译时增加-std=c++11的编译选项。(此处可参考《C++ Primer 第5版》P379页)

方法二和三,也可参考 http://www.cplusplus.com/reference/set/set/set/

  • 方法四:

为用户自定义类型特化std::less,不是很推荐,实现方法参考

https://www.cnblogs.com/huhu0013/p/4548522.html

 

在systemC/TLM中,新增的类型sc_time已经实现了operator< ,而tlm::tlm_generic_payload 并没有实现operator<,故其不能作为set/map的的key type。

/*
Original 2020-03-19
README:
    This is a example to teach you 
	how to use a self-defined type as the key in a map
	give three methods to realize 

execute:    
    g++ -g -Wall -O0 main.cpp  -o sim
	if use decltype keyword (C++ 11 feature), you need compile as 
		g++ -g -Wall -std=c++11 -O0 main.cpp  -o sim

*/

#include <iostream>
#include <map>
#include <set>

using namespace std;

class Test_Data
{
public:	
	//here must let Test_Data have a default constructor, 
	//		if not, you can't use Test_Data as a value type in a map
	//we set a default value to all parameter, 
	//		let this constructor as a default constructor
	Test_Data(unsigned int year = 0,
	 		unsigned int month = 0,
	  		unsigned int day = 0):
			m_year(year),
			m_month(month),
			m_day(day)		
			{}

	// method 1, you will find 2019,01,01 < 2019,02,02 if use this function
	// must add two const keyword here, if not, will compile error
	bool operator< (const Test_Data & cmp) const
	{
		if(m_year != cmp.m_year)
		{
			return (m_year < cmp.m_year) ;
		}
		else if (m_month != cmp.m_month)
		{
			return (m_month < cmp.m_month) ;
		}
		else
			return (m_day < cmp.m_day) ;	
	}

	//method 1, you will find 2019,01,01 > 2019,02,02 if use this function
	/*
	bool operator< ( const Test_Data & cmp) const
	{
		if(m_year != cmp.m_year)
		{
			return (m_year > cmp.m_year) ;
		}
		else if (m_month != cmp.m_month)
		{
			return (m_month > cmp.m_month) ;
		}
		else
			return (m_day > cmp.m_day) ;	
	}
	*/

	//here overload operator <<, shuold use const reference Test_Data 
	friend std::ostream& operator<< (std::ostream &os ,  const Test_Data & data)
	{
		os<<std::dec <<data.m_year <<"-"
					<<data.m_month <<"-"
					<<data.m_day;
		return os;			
	}

	public:
		unsigned int m_year;
		unsigned int m_month;
		unsigned int m_day;
};

// method 2
struct classcomp 
{
  	bool operator() (const Test_Data & lhs, const Test_Data & cmp) const
  	{
		if(lhs.m_year != cmp.m_year)
		{
			return (lhs.m_year < cmp.m_year) ;
		}
		else if (lhs.m_month != cmp.m_month)
		{
			return (lhs.m_month < cmp.m_month) ;
		}
		else
			return (lhs.m_day < cmp.m_day) ;
	}
};

//method 3
bool FunctionComp (const Test_Data & lhs, const Test_Data & cmp) 
{
	if(lhs.m_year != cmp.m_year)
	{
		return (lhs.m_year < cmp.m_year) ;
	}
	else if (lhs.m_month != cmp.m_month)
	{
		return (lhs.m_month < cmp.m_month) ;
	}
	else
		return (lhs.m_day < cmp.m_day) ;
}


int main(int argc, char** argv)
{
	Test_Data  a(2019,01,01);
	Test_Data  b(2019,02,02);
	Test_Data  c(2019,02,03);
	Test_Data  d(2020,02,02);

	// std::set<Test_Data >					m_test_set;	 // method 1
	// std::set<Test_Data, classcomp >		m_test_set;  // method 2

	// method 3  must add -std=c++11 when compile if use decltype
	// std::set<Test_Data, decltype(FunctionComp)* > m_test_set (FunctionComp); 

	// method 3 use function pointer
	bool(*fun_ptr)(const Test_Data & , const Test_Data &) = FunctionComp ;
	std::set<Test_Data, bool(*)(const Test_Data & , const Test_Data &) > m_test_set (fun_ptr); 

	m_test_set.insert(a);
	m_test_set.insert(b);
	m_test_set.insert(c);
	m_test_set.insert(d);

	std::set<Test_Data>::iterator it;
	unsigned int i =0;
	for ( it = m_test_set.begin(); it != m_test_set.end(); ++it, ++i)
	{
		//overload operator << must use const reference Test_Data 
		//or here will compile error for *it
		//because the return value of *it is temporary
		cout<<"["<<i<<"] data "<< *it <<endl;
	}

	// std::map<Test_Data , unsigned int >    			 m_test_map_1; // method 1
	// std::map<Test_Data , unsigned int, classcomp >    m_test_map_1; // method 2
	std::map<Test_Data , unsigned int, decltype(FunctionComp)* >    m_test_map_1 (FunctionComp); // method 3

	std::map< unsigned int, Test_Data >    m_test_map_2;
	std::map<Test_Data*, unsigned int >    m_test_map_3;

	m_test_map_1 [a] = 100;
	m_test_map_2 [100] = b;
	Test_Data * a_ptr  = new Test_Data (2020,10,10) ;
	m_test_map_3 [a_ptr] = 200;

	return 0;
}

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
C++ STL(Standard Template Library)是C++标准库中的一个重要组成部分,提供了一组数据结构和算法的模板类,可以大大简化C++程序的开发过程。STL包含了多个容器类,每个容器类都有其特定的特性和用途。 STL中的容器类主要分为序列容器关联容器两大类。序列容器包括vector、list、deque和array,它们按照元素在容器中的位置进行存储和访问。关联容器包括set、multiset、map、multimap和unordered系列容器,它们按照键值进行存储和访问。 序列容器具有以下特性: 1. 动态大小:序列容器可以根据需要动态调整大小,可以在任意位置插入和删除元素。 2. 快速随机访问:序列容器中的元素可以通过索引快速访问,时间复杂度为O(1)。 3. 按顺序存储:序列容器中的元素按照插入的顺序存储,并保持元素的相对位置不变。 4. 支持迭代器:序列容器提供了迭代器,可以通过迭代器遍历容器中的元素。 关联容器具有以下特性: 1. 自动排序:关联容器中的元素按照键值自动排序,并且可以根据自定义的比较函数进行排序。 2. 快速查找:关联容器支持快速的查找操作,时间复杂度为O(log n)。 3. 不允许重复键值:set和map容器中的键值是唯一的,而multiset和multimap容器允许重复的键值。 4. 无序容器:unordered系列容器是C++11引入的,它们使用哈希函数来存储和访问元素,查找操作的平均时间复杂度为O(1)。 总而言之,C++ STL提供了丰富的容器类,每个容器类都有其独特的特性和适用场景,可以根据具体需求选择合适的容器来存储和操作数据。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [C++——STL容器](https://blog.csdn.net/JAN6055/article/details/122758690)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [C++的STL容器类详解](https://blog.csdn.net/Jinyizhi2233/article/details/131640448)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

123axj

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值