头文件折腾记

看到Menci大神在github上放了一个头文件,感觉很不错的样子。 我也看够了写程序的时候在程序头上的一段声明和#define,于是就以此为契机开始写一下自己的头文件 我之前的程序在开头只有chkmx(),chkmn()和几个IO宏的定义,因为这些都是常用好写但每次都写比较烦的东西。平常在头文件里用这些,可以加快速度,也可以保证在考试之前能迅速写完。 但是之前还是把代码直接放在程序开头,为了美观还是尽量地精简了一下。现在写到头文件里面了,就不用怕是否精简咯。 第一个版本:

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
//Code by Lucida
#include<bits/stdtr1c++.h>
typedef long long int64;
namespace IO
{
#ifdef FastIO
const int IN=1e7,OUT=1e7;
#ifdef getchar
#undef getchar
#endif
#ifdef putchar
#undef putchar
#endif
char in[IN],*ip=in,*ie=in,out[OUT],*op=out,*oe=out+OUT;
#define getchar() ( (ip==ie && (ie=(ip=in)+fread(in,1,IN,stdin),ip==ie))?EOF:*ip++ )
inline void oflush() {
fwrite(out,1,op-out,stdout);
op=out;
}
#define putchar(x)( (op==oe?(oflush(),*op++):*op++)=(x) )
#endif
template <class T> inline void get(T &x) {
static bool f;static char ch;
for(f=0,ch=0;ch<'0' || '9'<ch;ch=getchar()) f|=ch=='-';
for(x=0;'0'<=ch && ch<='9';ch=getchar()) (x*=10)+=ch-'0';
x=f?-x:x;
}
#ifndef FastIO
template <> inline void get<double>(double &x) {
scanf("%lf",&x);
}
#endif
template <> inline void get<char>(char &x) {
while(x=getchar(),((x<'0' || '9'<x) && (x<'a' || 'z'<x) && (x<'A' || 'Z'<x)));
}
template <> inline void get<char*>(char *&x) {
char *cp=x;
while(*cp++=getchar(),(*cp!=' ' && *cp!='\r' && *cp!='\n' && *cp!=EOF));
*--cp=0;
}

template <class T> inline void put(T x) {
if(!x)
putchar('0');
else {
if(x<0) {
putchar('-');
x=-x;
}
static char stack[30]={0};
char *top=stack;
for(;x;x/=10) *++top=x%10+'0';
while(*top) putchar(*top--);
}
}
#ifndef FastIO
template <> inline void put<double>(double x) {
printf("%lf",x);
}
#endif
template <> inline void put<char>(char x) {
putchar(x);
}
template <> inline void put<char*>(char* x) {
while(*x)
putchar(*x++);
}
}

template <class T> inline bool chkmx(T &a,const T &b) {
return a<b?a=b,1:0;
}
template <class T> inline bool chkmn(T &a,const T &b) {
return a>b?a=b,1:0;
}

using std::swap;
using std::max;
using std::min;
using IO::get;
using IO::put;

用了一段时间,还是感觉不太爽,因为参数只能有一个,要一下读写一串还得写好几遍函数名。然而参数包模板是C++11才兹瓷的,而C的va_arg还要传一个终止符,感觉非常不爽。 于是就仿照cpp的IO流写了两个类 第二个版本

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
//Code by Lucida
#include<bits/stdtr1c++.h>
typedef long long int64;

namespace IO {
struct Ist {
template <class T> Ist &operator >>(T &x);
template <class T> Ist &operator >>(T *x);
}is;
template <class T> Ist &Ist::operator >>(T &x) {
static bool f;static char ch;
for(f=0,ch=0;ch<'0' || '9'<ch;ch=getchar()) f|=ch=='-';
for(x=0;'0'<=ch && ch<='9';ch=getchar()) (x*=10)+=ch-'0';
x=f?-x:x;
return *this;
}
template <class T> Ist &Ist::operator >>(T *x) {
while(*x++=getchar(),(*x!=' ' && *x!='\r' && *x!='\n' && *x!=EOF));
*--x=0;
return *this;
}
template <> Ist &Ist::operator >>(double &x) {
scanf("%lf",&x);
return *this;
}
template <> Ist &Ist::operator >>(char &x) {
while(x=getchar(),((x<'0' || '9'<x) && (x<'a' || 'z'<x) && (x<'A' || 'Z'<x)));
return *this;
}

struct Ost {
template <class T> Ost &operator <<(T x);
template <class T> Ost &operator <<(T *x);
}os;
template <class T> Ost &Ost::operator <<(T x) {
if(!x)
putchar('0');
else {
if(x<0) putchar('-'),x=-x;
static char stack[30]={0};
char *top=stack;
for(;x;x/=10) *++top=x%10+'0';
while(*top) putchar(*top--);
}
return *this;
}
template <class T> Ost &Ost::operator <<(T* x) {
while(*x) putchar(*x++);
return *this;
}
template <> Ost &Ost::operator <<(double x) {
printf("%lf",x);
return *this;
}
template <> Ost &Ost::operator <<(char x) {
putchar(x);
return *this;
}
}

template <class T> inline bool chkmx(T &a,const T &b) {
return a<b?a=b,1:0;
}
template <class T> inline bool chkmn(T &a,const T &b) {
return a>b?a=b,1:0;
}

using std::swap;
using std::max;
using std::min;
using IO::is;
using IO::os;

写的时候还学习了一下模板特化的原则

5.模板特化时的匹配规则 (1) 类模板的匹配规则 最优化的优于次特化的,即模板参数最精确匹配的具有最高的优先权 例子:

1
2
3
template <class T> class vector{//…//}; // (a)  普通型
template <class T> class vector<T*>{//…//}; // (b) 对指针类型特化
template <> class vector <void*>{//…//}; // (c) 对void*进行特化

每个类型都可以用作普通型(a)的参数,但只有指针类型才能用作(b)的参数,而只有void*才能作为(c)的参数 (2) 函数模板的匹配规则 非模板函数具有最高的优先权。如果不存在匹配的非模板函数的话,那么最匹配的和最特化的函数具有高优先权 例子:

1
2
3
4
5
6
7
8
9
10
11
12
template <class T> void f(T);  // (d)
template <class T> void f(int, T, double); // (e)
template <class T> void f(T*); // (f)
template <> void f<int> (int) ; // (g)
void f(double); // (h)
bool b;
int i;
double d;
f(b); // 以 T = bool 调用 (d)
f(i,42,d) // 以 T = int 调用(e)
f(&i) ; // 以 T = int* 调用(f)
f(d); // 调用(g)

所以就可以写一个对指针类型的模板,专门处理const char *char *了。 模板写的差不多了,难道在提交OJ的时候还要粘贴上吗?感觉非常不爽,于是怒写了一个OJ处理程序

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
#include <lucida>
#include <windows.h>
const char *headerfile="C:\\mingw4.4.5\\lib\\gcc\\i686-mingw32\\4.4.5\\include\\c++\\lucida";
using std::ifstream;
using std::ofstream;
using std::string;
using std::cout;
using std::cin;
using std::ios;

const int IN_SIZE=10000000;
void CtrlC(const char *sourcefile) {
FILE *infile=fopen(sourcefile,"r");
char *inbuf=(char*)malloc(IN_SIZE);
size_t length=fread(inbuf,1,IN_SIZE,infile);
fclose(infile);

HGLOBAL clipbuffer=GlobalAlloc(GMEM_DDESHARE,length);
char *buffer=(char*)GlobalLock(clipbuffer);
memcpy(buffer,inbuf,length);
GlobalUnlock(clipbuffer);

if(OpenClipboard(NULL)) {
EmptyClipboard();
SetClipboardData(CF_TEXT,clipbuffer);
CloseClipboard();
} else {
os<<"Access Denied\n";
}
//string cmd("clip < ");cmd+=sourcefile;system(cmd.c_str());
}
int main(int argc,char **argv) {
ifstream code(argv[1]),header(headerfile);
ofstream dest((string(strtok(argv[1],"."))+".oj").c_str(),ios::trunc);
string str;
while(getline(code,str))
{
if(str[0]!='\\') {
if(str.find("<lucida>")!=string::npos) {
while(getline(header,str))
dest<<str<<'\n';
continue;
}
if(str.find("freopen")!=string::npos)
dest<<"//";
dest<<str<<'\n';
}
else
dest<<str<<'\n';
}
code.close();
dest.close();
header.close();
#ifdef WIN32
CtrlC((string(strtok(argv[1],"."))+".oj").c_str());
#endif
return 0;
}

这样,只要在cmd中调用

1
oj *.cpp

就会生成*.oj文件,并把其中的内容写入剪贴板。 在实现自动复制的时候,还经历了一番周折:fread函数每次返回的size_t是对的,但是在fread到的数组里总是多了几行!!debug了好久才发现这个问题。。这也许是个C的bug吧。。 写完之后我忽然得知windows的cmd自带了clip命令,可以实现文件内容的复制。。但是试了试,汉字复制之后就乱码了233。。 头文件应该是会持续改动更新的吧。。