重拾c++感触
很久不用c++了,最近重新拾起,确实是很多地方让人无语
下面这段代码,是用vector与heap实现PriorityQueue
本来想想觉得简单得不得了,写起来才发现各种小问题调了我一整天。
//
// PriorityQueue.h
//
// Created by 姜孟冯 on 13-10-19.
// Copyright (c) 2013年 姜孟冯. All rights reserved.
//
#include <iostream>
#include <vector>
using namespace std;
/********************************************************
* class declaration
********************************************************/
template<class T, class COMP> class PriorityQueue;
/********************************************************
* friend functions
********************************************************/
// print the content of the priority queue, not in class PriorityQueue
template<class T, class COMP>
ostream& operator<<(ostream& o, PriorityQueue<T, COMP>& pq);
/********************************************************
* class defination
********************************************************/
/*
* This PriorityQueue class represents a priority queue. Use T as a node type
* and COMP as its comparator.
*/
template<class T, class COMP=greater<T>>
class PriorityQueue {
protected:
vector<T> _v; // use <vector> and <algorithm>'s heap
// function to build PriorityQueue
COMP _cmp; // compare function
public:
// changes the value of queue_element to new_element
void change_prioirity(const T& queue_element, const T& new_element);
// removes the top element of the queue.
void pop();
// does the queue contain queue_element.
bool contains(const T& queue_element) const;
// insert queue_element into queue
void insert(const T& queue_element);
// returns the top element of the queue.
const T& top() const;
// return the number of queue_elements.
int size() const;
PriorityQueue();
~PriorityQueue();
// print the content of the priority queue
friend ostream & operator<<<T, COMP>(ostream & o, PriorityQueue& pq);
};
//
// PriorityQueue.cpp
//
// Created by 姜孟冯 on 13-10-19.
// Copyright (c) 2013年 姜孟冯. All rights reserved.
//
#include "PriorityQueue.h"
#include <algorithm>
#include <functional>
/********************************************************
* friend functions
********************************************************/
// print the content of the priority queue
template<class T, typename COMP>
ostream& operator<<(ostream& o, PriorityQueue<T, COMP>& pq)
{
for (typename vector<T>::iterator iter = pq._v.begin(); iter != pq._v.end();
iter++)
{
if (iter != pq._v.begin())
{
o << ",";
}
o << *iter;
}
return o;
}
/********************************************************
* class PriorityQueue methods
********************************************************/
// constructor
template<class T, typename COMP>
PriorityQueue<T, COMP>::PriorityQueue()
{
make_heap(_v.begin(), _v.end(), _cmp);
}
// changes the priority (node value) of queue element.
// class T must implement method "T::set_value(V)"
template<class T, typename COMP>
void PriorityQueue<T, COMP>::change_prioirity(const T& queue_elemnt,
const T& new_element)
{
if (this->contains(queue_elemnt))
{
typename vector<T>::iterator iter = find(_v.begin(),
_v.end(), queue_elemnt);
*iter=new_element;
}
make_heap(_v.begin(), _v.end(), _cmp);
}
// removes the top element of the queue.
template<class T, typename COMP>
void PriorityQueue<T, COMP>::pop()
{
pop_heap(_v.begin(), _v.end(), _cmp);
_v.pop_back();
}
// does the queue contain queue_element.
template<class T, typename COMP>
bool PriorityQueue<T, COMP>::contains(const T& queue_element) const
{
return find(_v.begin(), _v.end(), queue_element) != _v.end();
}
// insert queue_element into queue
template<class T, typename COMP>
void PriorityQueue<T, COMP>::insert(const T& queue_element)
{
_v.push_back(queue_element);
push_heap(_v.begin(), _v.end(), _cmp);
}
// returns the top element of the queue.
template<class T, typename COMP>
const T& PriorityQueue<T, COMP>::top() const
{
return _v.front();
}
// return the number of queue_elements.
template<class T, typename COMP>
int PriorityQueue<T, COMP>::size() const
{
return static_cast<int>(_v.size());
}
由于感触颇深,所以作为一个c++外行,简单写写
1.谓词的问题
c++据我所知应该是没有匿名函数支持的,这简直不可思议
看看objective-c里的block、python里的lambda、ruby里的proc
这些都是好用得不得了的例子。
但c++里的谓词,我怎么用都觉得难用……
自定义函数类与继承结合要写在template里,我不知道这是不是标准用法,不过反正可行
template<class T, class COMP=greater<T>>
class PriorityQueue {
protected:
vector<T> _v; // use <vector> and <algorithm>'s heap
// function to build PriorityQueue
COMP _cmp; // compare function
bind2nd实在是个好用的函数,可以把一个二元函数绑定成一元。
有了它,那些stl里参数为的一元谓词的函数才变得好用。
比如any_of与find_if,网上找来找去都是这样的例子
bool isOdd(int i){
return i%2!=0
}
...
any_of(_v.begin(), _v.end(), isOdd);
...
有个毛用啊!!
但有了bind2nd之后,就可以这样写了
any_of(_v.begin(), _v.end(), bind2nd(_cmp, queue_element));
这是我昨天发现的最好用的c++函数
2.字符串转换的问题
一个简单到极点的int转sring的问题,在网上一搜,居然还有一大堆啰嗦的实现
有用sprintf的,有用stringstream的,还有用itoa的,我就想哭了……
难道中国程序员的c++水平还在98年么?
从C++11开始,用std::to_string(int)才是正常做法
3.random问题
这个不想细说了,还用%那真是上个世纪的写法。
#include<random>
#include<chrono>
...
unsigned int seed = static_cast<unsigned int>(std::chrono::system_clock::now().time_since_epoch().count());
default_random_engine generator(seed);
uniform_real_distribution<double> real_distribution(1.0, 10.0);
uniform_int_distribution<double> int_distribution(1, 10);
...
int a = int_distribution(generator);
double b = real_distribution(generator);
...
4.异常问题
还是贴代码
#include<stdexcept>
...
if (V < 0)
throw runtime_error("Number of vertices must be nonnegative");
5.模板的问题
这个是重点啊,来个三小点
1)模板与迭代器
我实在想不通 vector<T>::iterator iter这样定义一个迭代器有什么错。
查了很久才发现,要写typename vector<T>::iterator iter
2)模板与分离编译
模板类如果分开写在.h与.cpp里,连接器会报错。这与C++标准有关,因为只有调用才会实例化函数体。
在C++98的标准中,有export关键字,也就是在.cpp文件里这样写
export template<class T, typename V>
PriorityQueue<T, V>::PriorityQueue()
{
make_heap(_v.begin(), _v.end(), _cmp);
}
但是呢,主流编译器都不支持它,包括VS、g++以及xcode,因为这标准已经过期了
据说intel的compiler可以支持,反正我没用过。
目前解决方式是直接include .cpp文件,虽然这很不美╮(╯_╰)╭
- 模板与友元函数(坑爹的重重点)
这是错的!!声明的友元的函数是一个一般函数,不是下面定义的那个。template <class T> class PriorityQueue{ friend ostream & operator<< (ostream & o, PriorityQueue &pq); }; template <typename T> ostream & operator<<(ostream& o, PriorityQueue<T> &pq) { ... return o; }
这也是错的!!因为参数里的T和实例化PriorityQueue用的T被认为不一样。template <class T> class PriorityQueue{ friend ostream & operator<< (ostream & o, PriorityQueue<T> &pq); }; template <typename T> ostream & operator<<(ostream& o, PriorityQueue<T> &pq) { ... return o; }
这是模板函数的标准写法了,可还是错的。template <class T> class PriorityQueue{ friend ostream & operator<< <T> (ostream & o, PriorityQueue &pq); }; template <typename T> ostream & operator<<(ostream& o, PriorityQueue<T> &pq) { ... return o; }
真正的正确写法是前置声明,我对这个问题彻底无语。template <class T> class PriorityQueue; template <typename T> ostream & operator<<(ostream& o, PriorityQueue<T> &pq) { ... return o; } template <class T> class PriorityQueue{ friend ostream & operator<< <T> (ostream & o, PriorityQueue &pq); };