热爱互联网

有符号数和无符号数之间的操作

说多了都是泪,今天加班只为找到这个bug,………………….fuck


有符号数和无符号数之间的操作,编译器会先将有符号数转换成无符号数再进行运算。

看下面的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
using namespace std;
 
int main()
{
	unsigned int i = 3;
 
	if ( -1 < i )
		cout << "fuck" << endl;
	else
		cout << i << endl;
 
	unsigned int a = 10;
	int b = -20;
 
	cout << a+b << endl;
 
	return 0;
}
 
// output
/*
3
4294967286
*/

2013.8.4 这天也碰到这个问题,丫的,这回真的痛定思痛了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include<iostream>
#include<string>
#include <vector>
#include <stdlib.h>
using namespace std;
 
int main()
{
	string a = "hello", b = "world";
 
	vector< string > vsTemp;
 
	vsTemp.push_back( a );
	vsTemp.push_back(b );
 
	unsigned int j = -1;
	if ( j >= 0 )
		cout << "j == " << j << endl;     // j == 4294967295
 
 
	// 所以下面写循环是错误的,会死循环。
	// 正确的写法是注意点就是了,比如改成 int,。。。。
	for ( unsigned int i = vsTemp.size()-1 ; i >= 0 ; --i )
	{
		cout << vsTemp[i] << endl;
		cout << " i == " << i << endl;
		system("pause");
	}
 
	return 0;
}

C++11 正则表达式

先看这个入个门:http://www.cnblogs.com/zhuyp1015/archive/2012/04/08/2438191.html

然后详见:http://en.cppreference.com/w/cpp/regex

正则表达式的符号功能见百度百科:http://baike.baidu.com/view/94238.htm

还要考虑支持unicode字符,需要使用wstring,下面regex_match的一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>
#include <regex>
#include <string>
 
 
int main()
{
	std::locale::global(std::locale(""));
	std::wcout.imbue(std::locale());
 
	std::wstring resource = L"哈哈,I love you 就是我爱你的意思!!!";
 
	std::wstring patternStr;   // 例如: ".*就是我.*的意思.*" 或 ".*" 可以匹配 resource
 
	while( std::wcin >> patternStr )
	{
		const std::wregex pattern(patternStr);  // 把 patternStr 作为一个正则表达式在 resource 中去匹配
 
		if( std::regex_match(resource,pattern) )
		{
			std::wcout << L"成功匹配---" << patternStr << "---" << std::endl;
		}
		else
		{
			std::wcout << L"不匹配---" << patternStr << "---" << std::endl;
		}
	}
 
	return 0;
}

下面判断一个字符串中是否存在一个指定的子串,这个子串在程序被当做正则表达式处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <iostream>
#include <string>
#include <regex>
 
/***************************************************************
Description: 判断字符串 wsResource 中是否存在 wsPattern 这样的子表达式
Input:  字符串 wsResource 和 正则表达式 wsPattern
Output:
Return:  若存在则返回 true, 否则返回 false
Others:
****************************************************************/
 
bool ExistSubExpression(const std::wstring& wsResource,const std::wstring& wsPattern)
{
	std::wregex pattern(L".*"+wsPattern+L".*"); // 前缀和后缀可以为'n'之外的任何字符
	return std::regex_match(wsResource,pattern);
}
 
 
int main()
{
	std::locale::global(std::locale(""));
	std::wcout.imbue(std::locale());
 
	std::wstring wsResource = L"哈哈,I love you 就是我爱你的意思!!!";
 
	std::wstring wsPattern;
	wchar_t pTemp[50];
 
	while( std::wcin.getline(pTemp,50) )   // 这样就可以包含空格在wsPattern中
	{
		wsPattern.assign(pTemp);
 
	//	std::wcout << wsPattern << std::endl;
	//	std::wcout << pTemp << std::endl;
 
		if ( ExistSubExpression(wsResource,wsPattern) )
		{
			std::wcout << L"存在---" << wsPattern << std::endl;
		}
		else
		{
			std::wcout << L"不存在---" << wsPattern << std::endl;
		}
	}
 
 
	return 0;
}

locale以及字符串安全函数

strcpy 和 strncpy 等等 都是不安全的函数, 放心,默认情况下,vs2012 会编译报错的。
安全函数一般的后缀为 _s , 例如 宽字符的拷贝函数 wcsncpy_s 。

如果要使用 宽字符 的话需要用到 locale ,详见:c++的本地化库 http://zh.cppreference.com/w/cpp/locale

还有一些 微软 的安全函数 ,包含在 strsafe.h 中, 详见 msdn http://msdn.microsoft.com/zh-CN/library/ms647466.aspx

看下面这个例子,在vs2012下编译运行(在vs2005运行有错),另外 wcsncpy 在 vs2005 中仅仅是给出 deprecated 的 警告错误,而在 vs2012 中却直接给出error, 看来还是 vs2012 靠谱。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#include <iostream>
#include <locale>
#include <string>
//#include <strsafe.h>
 
int main()
{
	std::wcout << std::locale("").name().c_str() << std::endl;
	std::wcout << 1000.01 << std::endl;   // 1000.01
 
	std::locale::global(std::locale(""));
	std::wcout.imbue(std::locale());  // use the new global locale for future wide character output
 
	std::wcout << 1000.01 << std::endl; // 1,000.01
 
 
 
	std::wstring str = L"你好a,我是lijie,嘿";
	std::wcout << str << std::endl;  // 你好a
	std::cout << str.length() << std::endl;  // 13
 
	str[2] = L'啊';
 
	for( int i=0; i<str.length(); ++i )  // 你 好 啊
	{
		std::wcout << str[i] << " ";
	}
	std::cout << std::endl;
 
 
	if( L'啊' == str[2] )
	{
		std::cout << "is 啊" << std::endl;
	}
 
	if( std::isalpha('a',std::locale() ) )
	{
		std::cout << "是字母" << std::endl;
	}
 
	wchar_t wc[] = L"我爱你";
	std::wcout << wc << std::endl;
	std::cout << std::wcslen(wc) << std::endl;  // 3
	std::cout << sizeof(wc) << std::endl;   // 8
 
	wchar_t wstemp[4];
	std::cout << std::wcslen(wstemp) << std::endl;  // 1
	std::wcout << sizeof(wstemp) << std::endl; // 8
	std::cout << sizeof(wchar_t) << std::endl; // 2
 
 
	//这是不安全函数,编译器报错,汗
    //std::wcsncpy( wstemp,wc,sizeof(wstemp)/sizeof(wchar_t) );
 
	// 这样可以
    //std::wstring wdest(wc);
 
	//使用安全函数,一般后缀都带有 _s 标记
	std::cout << _countof(wc) << std::endl;  // 4, 包含串结束符
	wcsncpy_s( wstemp, wc, _countof(wc) );
	std::wcout << wstemp << std::endl;
	if( '' == wstemp[3] )
	{
		std::cout << "haha" << std::endl;
	}
 
	std::cout.imbue(std::locale("french_france"));
	double x = 1234567.123456;
 
	std::cout << x << std::endl;  // 1,234566e+006
 
	return 0;
 
}

实习 — 第一周

7.11号入的职,不算周末的话,也在公司呆了7天了,写个一周总结好了。

先叙述一下这段时间的状态。

7.11,7.12 培训,主要是介绍公司文化,制度等。
7.13 (周六)在酒店睡大觉,三星级的酒店就是舒服,嚯嚯。
7.14 和菊花哥一起去找房子了,最后因为定金太贵没谈成。

7.15 星期一, 上午是我们业务开发组的例会,前辈们分享了c++的测试框架GTest和GMock,
好吧,我没听过,回去果断谷歌,下午在VS2005上了搭建了GTest和GMock的环境,
尝鲜了下,感觉GTest和boost里面的test差不多,又接触到了新的东西,很有爱。

7.16– 7.19 期间各种培训,没什么好说的。其余时间在denny大哥的指导下
玩了下python,由于以前接触过python,所以上手很快,主要学了下python的文件操作,
以及Django框架,然后用 Django + python + mysql + html 写了个页面显示mysql数据库
中的数据。

然后 7.20,7.21又是周末了。。。。。

总的来说,这个星期感觉还行,大tx的氛围果然不错。不过还有很多东西都需要去学习。
下个星期就启动 mini项目–QQ搜索 了,非常期待。。

GTest and GMock

分享会上听到的,果断学一下。
Google开源C++单元测试框架的简称为GTest。
GTest详见:http://www.cnblogs.com/coderzh/archive/2009/04/06/1426755.html
GMock详见:http://heuristic-cookbook.appspot.com/Google-Mock-%E5%85%A5%E9%97%A8

c++ 11 —- weak_ptr

详见:http://en.cppreference.com/w/cpp/memory/weak_ptr

weak_ptr 是为配合 shared_ptr 而引入的一种智能指针,它更像是 shared_ptr 的一个助手而不是智能指针,因为它不具有普通指针的行为,
没有重载 operator* 和 -> 。它的最大作用在于协助 shared_ptr 工作,像旁观者那样观测资源的使用情况。(这段话来自于《boost程序库完全开放指南 第二版》)

weak_ptr 保存一个已经被shared_ptr管理了的对象的weak_reference(弱引用),必须转换成shared_ptr 才能访问这个对象(用lock()转化)。
弱引用并不修改该对象的引用计数,这意味这弱引用它并不对对象的内存进行管理,在功能上类似于普通指针,然而一个比较大的区别是,弱引用能检测到所管理的对象是否已经被释放,从而避免访问非法内存。

下面是一个小例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include<iostream>
#include<string>
#include<memory>
using namespace std;
 
weak_ptr<int> gw;
 
void f()
{
	if(gw.expired()){ // 用 expired() 也可以判断指针是否过期
		cout << "gw.expired(): gw is expired" <<endl;
	}
 
	if(auto spt = gw.lock()){ // 在使用之前必须copy到一个shared_ptr
		cout << *spt << endl;
	}
	else{
		cout << "gw is expired" <<endl;
	}
}
 
int main()
{
	{
		auto sp = make_shared<int>(42);
		gw = sp;
 
		cout << sp.use_count() <<endl;  // 仍然是 1
 
		f();
	}
 
	f();
 
	auto p = make_shared<int>(10);
 
	weak_ptr<int> q = p;
 
	//cout << *g <<endl;   // 非法,必须用 lock() 转化成 shared_ptr 才可以访问对象
 
	cout << *q.lock() <<endl;
 
	return 0;
}

c++ 11 —- shared_ptr

详见:http://en.cppreference.com/w/cpp/memory/shared_ptr

shared_ptr 是通过指针保持某个对象的共享拥有权的智能指针。若干个 shared_ptr 对象可以拥有同一个对象;最后一个指向该对象的 shared_ptr 被销毁或重置时,该对象被销毁。销毁该对象时使用的是 delete 表达式或者是在构造 shared_ptr 时传入的自定义删除器(deleter)。

下面是个小例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include<iostream>
#include<string>
#include<memory>
using namespace std;
 
struct Foo{
	Foo(){
		cout << "Foo..." <<endl;
	}
	~Foo(){
		cout << "~Foo..." <<endl;
	}
};
 
struct D{
	void operator()(Foo* p) const{
		cout << "call delete for Foo object..." <<endl;
		delete p;
	}
};
 
int main()
{
	shared_ptr<foo> sh1;
 
	shared_ptr<foo> sh2(new Foo);
	shared_ptr<foo> sh3(sh2);
 
	cout << sh2.use_count() << endl;
	cout << sh3.use_count() << endl;
 
	shared_ptr<foo> sh4(new Foo,D());
 
	shared_ptr<foo> sh5 = sh4;
 
	cout << "hello world" <<endl;
 
	return 0;
}

c++ 11 —- unique_ptr

详见:
http://en.cppreference.com/w/cpp/memory/unique_ptr

把 en 改成 zh 即可看中文版的,不过是通过google翻译过来的,有一些翻译不是很准确:
http://zh.cppreference.com/w/cpp/memory/unique_ptr

unique_ptr 是一个智能指针:
(1)保留了唯一的一个对象的所有权通用指针,不能拷贝或复制。
(2)在unique_ptr超出作用域后会自动destroy所指向的对象。
下面是个小例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include<iostream>
#include<string>
#include<memory>
using namespace std;
 
struct Foo{
	Foo() { cout<<"foo::foo" <<endl; }
	~Foo(){ cout << "Foo::" <<endl; }
	void bar() { cout<< "Foo::bar" <<endl; }
};
 
void f(const Foo& foo)
{
	cout << "f(const Foo& foot)" <<endl;
}
 
int main()
{
	unique_ptr<foo> p1(new Foo);
	if(p1)
		p1->bar();
 
	{
		unique_ptr<foo> p2(move(p1));
 
		if(p1 == nullptr)
			cout << "p1 is nullptr" <<endl;
 
		f(*p2);
 
		p1 = move(p2);
 
		cout << "destroying p2..." <<endl;
	}
 
	if(p1)
		p1->bar();
 
	return 0;
}

c++ 11 —- unordered_set unordered_map

详见: http://www.cplusplus.com/reference/unordered_set/unordered_set/
http://www.cplusplus.com/reference/unordered_set/unordered_multiset/
http://www.cplusplus.com/reference/unordered_map/unordered_map/
http://www.cplusplus.com/reference/unordered_map/unordered_multimap/

unordered_set,unordered_map 的原理是一样的,都是开链哈希,不解释了。
他们不保证任何顺序(包括输出),不能更改key,只能删除和插入。
unorderer_multiset ,unordered_multimap 则允许重复的值。

四种容器大同小异,下面以 unordered_set 作为例子:
基本操作如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#include<iostream>
#include<unordered_set>
#include<unordered_map>
using namespace std;
 
/*
	template< class key,   					 // unordered_set::key_type/value_type
			  class Hash = hash<key>,		 // unordered_set::hasher
			  class Pred = equal_to<key>,	 // unordered_set::key_equal
			  class Alloc = allocator<key>,	 // unordered_set::allocator_type
			> class unordered_set;
*/
 
template<typename T>
T cmerge(T a,T b)
{
	T t(a);
	t.insert(b.begin(),b.end());
	return t;
}
 
int main()
{
	// constructor
	unordered_set<string> us1;
	unordered_set<string> us2 = {"red","green","blue"};
	unordered_set<string> us3(us2);
 
	unordered_set<string> us4 (cmerge(us2,us3));
	unordered_set<string> us5 (us4.begin(),us4.end());
 
	for(auto x : us5)
		cout << x << " ";
	cout << endl;
 
	us1 = us2;
	for(auto x : us1)  // blue red green ,输出并不保证顺序
		cout << x << " ";
	cout << endl;
 
	// capacity and buckets
	cout << us1.empty() <<endl;  // 0
	cout << us1.size() <<endl;   // 3
	cout << us1.max_size() <<endl; // 357913941
 
	unordered_set<int> us6;
	cout << us6.empty() <<endl;   // 1
	cout << us6.max_size() <<endl;  // 536870911
	cout << us6.max_bucket_count() <<endl;  // 536870911
	cout << us6.max_load_factor() <<endl;  // 1
	cout << us6.bucket_count() <<endl;  // 11
	cout << us6.load_factor() <<endl;  // 0
 
	// iterators
	for(auto iter = us5.begin(); iter != us5.end(); ++iter)
		cout << *iter << " ";
	cout << endl;
 
	// element lookup and modifiers
	if( us5.find("lijie") == us5.end() )
		cout << "none" <<endl;
 
	cout << us5.count("lijie") <<endl; // 0
	cout << us5.count("red") <<endl;  // 1
 
	us5.insert("lijie");
	for(auto x : us5)
		cout << x << " ";
	cout <<endl;
 
	us5.erase("lijie");   // erasing by key
	// us5.erase(us5.find("lijie"));  // erasing by iterator
 
	us5.erase( us5.find("red"), us5.end() ); // erasing by range
	for(auto x : us5)
		cout << x << " ";
	cout <<endl;
 
	// hash policy and observers
	unordered_set<string> myset;
	myset.rehash(12);
 
	myset.insert("office");
	myset.insert("house");
	myset.insert("gym");
	myset.insert("parking");
	myset.insert("highway");
 
	cout << myset.bucket_count() <<endl;  // 7
 
	// hash function
	unordered_set<string>::hasher fn = myset.hash_function();
 
	cout << fn("that") << endl;
	cout << fn("than") << endl;
 
	// comparisons
	unordered_set<string>
	a = {"AAPL","MSFT","GOOG"},
	b = {"MSFT","GOOG","AAPL"},
	c = {"MSFT","GOOG","AAPL","ORCL"};
 
	if( a == b ) cout << " a and b are equal " <<endl;
	if( b != c ) cout << " b and c are not equal " <<endl;
 
	return 0;
}

下面是自定义自己的hash函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include<iostream>
#include<string>
#include<unordered_set>
using namespace std;
 
struct Node
{
	string a;
	int b;
	char c;
 
	Node(string _a,int _b,char _c): a(_a),b(_b),c(_c) { }
};
 
template<typename T>
struct myhash
{
	int operator()(const T& a) const  // 用 b 来做 key
	{
		return a.b % 100;
	}
};
 
template<typename T>
struct myequal
{
	bool operator()(const T& a,const T& b) const  // 用 c 来作为值比较大小
	{
		return a.c == b.c;
	}
};
 
int main()
{
	unordered_set<node,myhash<node>,myequal<node>> us;
 
	Node a("lijie",520,'c'),b("dou",52,'d');
	us.insert(a);
	us.insert(b);
 
	for(auto x : us)
		cout << x.a << " " << x.b << " " << x.c <<endl;
 
	return 0;
}

c++ 11 —- array

http://www.cplusplus.com/reference/array/array/
一个数组而已,下面是例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#include <iostream>
#include <array>
#include <cstring>
#include <tuple>
using namespace std;
 
int main()
{
	array<int,5> arr = {1,3,4,5,2};
 
	/* iterators: begin,end,rbegin,rend,cbegin,cend,crbegin,crend  */
	// 1 3 4 5 2
	for(auto iter = arr.begin(); iter != arr.end() ; ++iter)
		cout << *iter << " ";
	cout << endl;
	// can't modify *iter
	for(auto iter = arr.cbegin(); iter != arr.end(); ++iter)
		cout << *iter << " ";
	cout << endl;
 
	// 2 5 4 3 1
	for(auto iter = arr.rbegin(); iter != arr.rend(); ++iter)
		cout << *iter << " ";
	cout << endl;
	// can't modify *iter
	for(auto iter = arr.crbegin(); iter != arr.crend(); ++iter)
		cout << *iter << " ";
	cout << endl;
 
 
	/*  capacity: size, max_size, empty  */
	// size and max_size of an array object always match.
	cout << arr.size() <<endl;   // 5
	cout << arr.max_size() <<endl; // 5
	cout << arr.empty() <<endl; // 0
 
 
	/*  elements access: operator[], at, front, back, data  */
	// arr[n],arr.at(n);  array::at checks the array bounds and
	// signals whether n is out of range  by throwing an exception.
	// array::data, return pointer to the data contained by the array object.
	for(int i=0; i < arr.size(); ++i)
		cout << arr[i] << " ";
	cout << endl;
 
	for(int i=0; i < arr.size(); ++i)
		cout << arr.at(i) << " ";
	cout << endl;
 
	cout << arr.front() <<endl; // 1
	cout << arr.back() <<endl;  // 2
 
	array<char,5> arr1 = {'h','e','l','l','o' };
	cout << arr1.data() <<endl;  // hello
 
	const char* cstr = "hello world";
	array<char,11> arr2;
	memcpy(arr2.data(),cstr,11);
	cout << arr2.data() <<endl; // hello world
 
 
	/*  modifiers: fill, swap  */
	array<int,5> arr3;
	arr3.fill(6);
	for(auto x : arr3)   // 6 6 6 6 6
		cout << x << " ";
	cout <<endl;
 
	array<int,5> arr4;
	arr4.fill(9);
	arr4.swap(arr3); // swap
 
	for(auto x : arr4) // 6 6 6 6 6
		cout << x << " ";
	cout << endl;
 
	for(auto x : arr3) // 9 9 9 9 9
		cout << x << " ";
	cout << endl;
 
	/* non-member function overloads. get(array), relational operators(array) */
	array<int,3> arr5 = {10,20,30};
	tuple<int,int,int> tu(1,2,3);
 
	tuple_element<0,decltype(arr5)>::type myelement;
	myelement = get<2>(arr5);
	get<2>(arr5) = get<0>(arr5);
	get<0>(arr5) = myelement;
 
	cout << get<0>(arr5) << " " << get<2>(arr5) <<endl;
	cout << get<0>(tu) << " " << get<1>(tu) << " " <<get<2>(tu) << endl;
 
	// array comparisons
	array<int,3> a = { 1,2,3 };
	array<int,3> b = { 1,2,3 };
	array<int,3> c = { 4,5,6 };
 
	if( a == b ) cout << "a and b are equal" <<endl;
	if( b != c ) cout << "b and c are not equal" <<endl;
	if( b < c )  cout << "b is less than c" <<endl;
	if( c > b )  cout << "c is greater than b" <<endl;
	if( a <= b ) cout << "a is less than or equal to b" <<endl;
	if( a >= b ) cout << "b is greater than or equal to a" <<endl;
 
 
 
	/*  non-member class specializations.
	 *  tuple_element<array>, tuple_size<array>
	 *  */
	// tuple_element
	auto tu1 = make_tuple(10,'a');
	array<int,4> d = {1,2,3,4};
 
	tuple_element<0,decltype(tu1)>::type first = get<0>(tu1);
	tuple_element<1,decltype(tu1)>::type second = get<1>(tu1);
	cout << first << " " << second <<endl;   // 10 a
 
	tuple_element<2,decltype(d)>::type third = get<2>(d);
	cout << third << endl;  // 3
 
	// tuple_size
	cout << tuple_size<decltype(tu1)>::value << endl;
 
	cout << tuple_size<decltype(d)>::value << endl;
 
	return 0;
}