同名函数的选择
- 同名函数的情况,可以出现于函数重载或者有模板函数的情况下,弄清各个函数的调用优先级以及报错的情况有必要
void may(int);
float may(float, float y=3);
void may(char);
char * may(const cahr & );
template<class T> void may(const T &);
template<class T> void may(T *);
编译器选择匹配的函数顺序如下 :
1. 完全匹配。参数列表和返回类型完全匹配,不需要任何转化。其中,常规函数>显示具体化>普通模板.
2. 提升转换。形参和实参并非完全匹配,带入的实参会自动转化为形参的类型,精度不会改变,是安全的转化。char short 转为 int, float 转为double
3. 标准转化。可能会丢失精度。int 转为 char ,long 转为double。
完全匹配 和最佳匹配
- 以下的转化都可以视为完全匹配,其中type 泛指任何一种类型。
实参 | 形参 |
---|---|
type | type & |
type & | type |
type [] | *type |
type (arguement-list) | type * (arguement-list) |
type | const type |
type | volatile type |
type * | const type |
type * | volatile type* |
所以,以下4个都是完全匹配,从报错中明显可见
void test(int);
void test( const int);
void test(int &);
void test(const int &);
- 只有上面的第1 、2个,由于完全匹配将会编译出错,这个并不难理解,编译器发现了两个都可以匹配的不知道匹配哪个。
- 只有第3、4个,编译没有任何问题。并且可以看出,选择的是无const 版本,对于引用类型和指针类型都是这样。而对于实参是const 的类型, 由于非const指针不能指向const,选取const形参函数是理所应当的。
void test(int &)
{
cout << " I'm void test(int &);" << endl;
}
void test(const int &)
{
cout << " I'm void test(const int &);" << endl;
}
void test(int *)
{
cout << " I'm void test(int *);" << endl;
}
void test(const int *)
{
cout << " I'm void test(const int *);" << endl;
}
int main()
{
int a = 5;
const int b = 10;
test(a);
test(b);
test(&a);
test(&b);
cin.get();
return 0;
}
自定义匹配
- 也就是使用者指定使用哪个,比如虽然有模板和普通函数,由于某些原因,我希望编译器使用模板。
void cal(double x, double y)
{
cout << "int cal(int x, int y) :" << x+y <<endl;
}
template <typename T>
void cal(T x, T y)
{
cout << "T cal(T x, T y) :" <<x+y <<endl;
}
int main()
{
double x = 1.6;
double y = 2.7;
cal(x,y);
cal<>(x, y);
cal<int >(x, y);
cin.get();
return 0;
}
从结果看,确实根据使用者需要,调用了相应的函数。
无法确定的模板变量类型处理
template <typename T1, typename T2>
void test(T1 x ,T2 y)
{
A =x+y;
}
对于上述的代码将会出现一个问题,无法预先知道A的类型。可以使用函数decltype()
decltype(x+y) A =x+y;//根据x+y的类型确定变量类型,由编译器确定
//对于函数返回类型
template <typename T1, typename T2>
auto test(T1 x ,T2 y) ->decltype(x+y);
1、volatile进行优化,强制编译器从硬件中读取。虽然程序没有改变某个内存的值,但是硬件可能根据条件使内存变化,比如串口接受数据
2、mutable 指出,即使结构体或者变量被定义为const类型,内部的某个参数仍然可变。
struct data
{
mutable int a;
int b;
}
const data x ={1, 2};
x.a=5; //这是可行的
3
名空间
定义一个名空间
namespace Jack{
double x;
int y;
}
- 为名空间扩展内容;为名空间内的函数实现定义
namespace Jill{
char *goose (const char *);
}
namespace Jack{
void test()
{
}
}
- 名空间作用域解析,
Jack::x=3.5;
Jack::y=8;
using声明 和 using编译指令
- 为了免去每次使用名空间解析的繁琐,可以使用using 一次性声明某个名空间内的内容。使得解析后的内容的可用范围在使用using声明块内。
int main()
{
using Jill::test;
}
- 使用using 编译指令使得对应名空间内内容均可用
using namespace Jill;