太原网站制作定制开发,江北seo,短视频seo询盘获客系统软件,网站建设工作量评估报价表一、动静态类型
静态类型#xff1a;使用前需要声明和定义。
动态类型#xff1a;无需声明直接使用(需要定义)。如Python、Perl、JavaScript
本质区别在于类型检查时机#xff0c;静态在编译期#xff0c;动态在运行时(依赖类型推导)
C11引入了两种类型推导#xff1a…一、动静态类型
静态类型使用前需要声明和定义。
动态类型无需声明直接使用(需要定义)。如Python、Perl、JavaScript
本质区别在于类型检查时机静态在编译期动态在运行时(依赖类型推导)
C11引入了两种类型推导auto和decltype。两者都是静态类型因此必须是编译期推导的类型。
而且auto声明必须定义否则无法推导。实际上auto不是类型只是类型占位符在编译期推导成功后进行类型替换。
二、auto优势
简化代码
#include string
#include vector
void loopover(std::vectorstd::string vs) {std::vectorstd::string::iterator i vs.begin(); // 想要使用iterator往往需要书写大量代码for (; i vs.end(); i) {// 一些代码}
}
#include string
#include vector
void loopover(std::vectorstd::string vs) {for (auto i vs.begin(); i vs.end(); i) {// 一些代码}
}
对比上述两例代码可以看到使用auto能够简化代码类型。
避免声明出错尤其是有隐式转换的操作时
class PI {
public:
double operator* (float v) {return (double)val * v; // 这里精度被扩展了
}
const float val 3.1415927f;
};
int main() {float radius 1.7e10;PI pi;auto circumference 2 * (pi * radius);
}
上述代码radius未float类型而在经过计算之后得到的circumference精度得到了扩展(double)而有时我们容易依赖原有类型将circumference声明为float类型这就使得计算结果精度降低了。
而使用auto则会自动推导为double类型。
但是对于计算溢出的场景自动推导并不能扩展其类型(因为只能对类型结果推导而不能对计算结果推导)
#include iostream
using namespace std;
int main() {unsigned int a 4294967295; //最大的unsigned int值unsigned int b 1;auto c a b; // c的类型依然是unsigned intcout a a endl; // a 4294967295cout b b endl; // b 1cout a b c endl;// a b 0return 0;
}
上述仍然会将c推导为unsigned int类型而非更大存储范围的unsigned long。
自适应性在模板上的支持
templatetypename T1, typename T2
double Sum(T1 t1, T2 t2) {auto s t1 t2; // s的类型会在模板实例化时被推导出来return s;
}
int main() {int a 3;long b 5;float c 1.0f, d 2.3f;auto e Sumint ,long(a, b); // s的类型被推导为longauto f Sumfloat,float(c, d); // s的类型被推导为float
}
// 编译选项:g -stdc11 4-2-7.cpp可以自动推导多个输入类型参数计算后的结果类型。当然这里来看仍然需要要求为double类型(因为返回值为double)但是实际上结合后面的decltype可以实现追踪返回类型从而将返回类型也实现自动推导。
宏上的使用
#define Max1(a, b) ((a) (b)) ? (a) : (b)
#define Max2(a, b) ({ \
auto _a (a); \
auto _b (b); \
(_a _b) ? _a: _b; })
int main() {int m1 Max1(1*2*3*4, 5678);int m2 Max2(1*2*3*4, 5678);
}
我们定义了两种类型的宏Max1和Max2。两者作用相同都是求a和b中较大者并返回。前者采用传统的三元运算符表达式这可能会带来一定的性能问题。因为a或者b在三元运算符中都出现了两次那么无论是取a还是取b其中之一都会被运算两次。而在Max2中我们将a和b都先算出来再使用三元运算符进行比较就不会存在这样的问题了
三、auto使用细则
不继承
int x;
int * y x;
double foo();
int bar();
auto * a x; // int*
auto b x; // int
auto c y; // int*
auto * d y; // int*
auto * e foo(); // 编译失败, 指针不能指向一个临时变量
auto f foo(); // 编译失败, nonconst的左值引用不能和一个临时变量绑定
auto g bar(); // int
auto h bar(); // int
auto不继承引用所以如果需要引用时需要自己添加否则可能会引起拷贝从而导致性能问题。
不继承cv限制符
double foo();
float * bar();
const auto a foo(); // a: const double
const auto b foo(); // b: const double
volatile auto * c bar(); // c: volatile float*
auto d a; // d: double
auto e a; // e: const double
auto f c; // f: float *
volatile auto g c; // g: volatile float *
同引用一样auto不会继承const和volatile关键字需要自己添加。
忽略*
#include type_traits
#include iostream
using namespace std;
int i 1;
int j i;
int * p i;
const int k 1;
int main() {auto* v3 p; // v3的类型是int*v3 i;
}
auto在进行类型推导时会对auto后冗余的*进行忽略如p通过自动推导为int *而auto*则不会被认为是int **,而是int *。
有些场合不适用
#include vector
using namespace std;
void fun(auto x 1){} // 1: auto函数参数无法通过编译
struct str{
auto var 10; // 2: auto非静态成员变量无法通过编译
};
int main() {char x[3];auto y x;auto z[3] x; // 3: auto数组无法通过编译// 4: auto模板参数实例化时无法通过编译vectorauto v {1};
}
// 编译选项:g -stdc11 4-2-13.cpp1对于函数fun来说auto不能是其形参类型。如果需要泛型的参数还是需要求助于模板。
2对于结构体来说非静态成员变量的类型不能是auto的。同样的由于var定义了初始值读者可能认为auto可以推导str成员var的类型为int的。但编译器阻止auto对结构体中的非静态成员进行推导即使成员拥有初始值。
3声明auto数组。我们可以看到main中的x是一个数组y的类型是可以推导的而声明auto z[3]这样的数组同样会被编译器禁止。
4在实例化模板的时候使用auto作为模板参数如main中我们声明的vectorauto v。虽然读者可能认为这里一眼而知是int类型但编译器却阻止了编译。