广州外贸型网站设计,wordpress中文4.8,建设网站多长时间,摄影之友官网一、typeof与typeid
1.1、typeof
在C11标准之前#xff0c;GCC已经提供了一个类似功能的运算符 typeof对类型进行推导#xff0c;但是这毕竟是编译器的实现#xff0c;不是标准。
int a 0;
typeof(a) b 5;1.2、typeid
C标准提供了 typeid 运算符#xff0c;获取的类型…一、typeof与typeid
1.1、typeof
在C11标准之前GCC已经提供了一个类似功能的运算符 typeof对类型进行推导但是这毕竟是编译器的实现不是标准。
int a 0;
typeof(a) b 5;1.2、typeid
C标准提供了 typeid 运算符获取的类型信息会包含在一个类型为std::type_info的对象里可以调用成员函数name获取其类型名。
int x1 0;
double x2 5.5;
std::cout typeid(x1).name() std::endl;
std::cout typeid(x1 x2).name() std::endl;
std::cout typeid(int).name() std::endl;成员函数name返回的类型名在C标准中并没有明确的规范所以输出的类型名会因编译器而异。 typeid的返回值是一个左值生命周期直到当前函数周期结束 typeid返回的std::type_info删除了复制构造函数若想保存std::type_info只能获取其引用或者指针 auto t1 typeid(int); // 编译失败没有复制构造函数无法编译auto t2 typeid(int); // 编译成功t2推导为const std::type_infoauto t3 typeid(int); // 编译成功t3推导为const std::type_info*typeid的返回值总是忽略类型的 cv 限定符也就是typeid(const T) typeid(T))。
很明显typeid有很大缺陷它并不能像typeof那样在编译期就确定对象类型。
二、decltype
为了用统一方法解决上述问题C11标准引入了decltype说明符使用decltype说明符可以获取对象或者表达式的类型其语法与typeof类似
int x1 0;
decltype(x1) x2 0;
std::cout typeid(x2).name() std::endl; // x2的类型为intdouble x3 0;
decltype(x1 x3) x4 x1 x3;
std::cout typeid(x4).name() std::endl; // x1x3的类型为doubledecltype({1, 2}) x5; // 编译失败{1, 2}不是表达式为了更好的讨论decltype的优势需要用到返回类型后置。
auto sum(int a1, int a2)-int {return a1a2;
}上述代码中以C11为标准auto作为占位符并不能使编译器对函数返回类型进行推导必须使用返回类型后置的形式指定返回类型。如果想泛化这个函数就需要用到函数模板
templateclass R, class T1, class T2
R sum(T1 a1, T2 a2) {return a1 a2;
}auto x3 sumdouble(5, 10.5);满足泛化sum函数的要求但必须为函数模板指定返回值类型。如何在编译期完成所有的类型推导工作
templateclass T1, class T2
auto sum(T1 a1, T2 a2)-decltype(a1 a2) {return a1 a2;
}auto x4 sum(5, 10.5);decltype 完美地解决了之前需要指定返回类型的问题。在实例化sum函数的时候编译器就能够知道sum的返回类型了。 C14标准中直接支持了对auto声明的返回类型进行推导 templateclass T1, class T2
auto sum(T1 a1, T2 a2) {return a1 a2;
}但是auto还存在一些小问题 templateclass T
auto return_ref(T t) {return t;
}int x1 0;
static_assert(std::is_reference_vdecltype(return_ref(x1))// 编译错误返回值不为引用类型
);上述代码中 auto 直接被推导为值类型使用auto声明变量初始化时目标对象如果是引用则引用属性会被忽略导致编译错误 三、推导规则
decltype(e)其中e的类型为T 1 如果e是一个未加括号的标识符表达式结构化绑定除外或者未加括号的类成员访问则decltype(e)推断出的类型是e的类型T。如果并不存在这样的类型或者e是一组重载函数则无法进行推导。 2如果e是一个函数调用或者仿函数调用那么decltype(e)推断出的类型是其返回值的类型。 3如果e是一个类型为T的左值则decltype(e)是T。 4如果e是一个类型为T的将亡值则decltype(e)是T。 5除去以上情况则decltype(e)是T。 看几个例子
const int foo();
int i;
struct A {double x;
};
const A* a new A();decltype(foo()); // decltype(foo())推导类型为const int 满足规则4
decltype(i); // decltype(i)推导类型为int 满足规则1
decltype(a-x); // decltype(a-x)推导类型为double 满足规则1
decltype((a-x)); // decltype((a-x))推导类型为const double 满足规则3加了括号就是表达式,表达式返回左值还有const修饰所以 (a-x) 的类型是 const double即指向 x 的常量引用。int i;
int *j;
int n[10];
decltype(i0); // 推导类型为int 表达式返回左值
decltype(0,i); // 推导类型为int 逗号表达式返回第二个值
decltype(i,0); // 推导类型为int
decltype(n[5]); // 推导类型为int 数组n中的第6个元素左值
decltype(*j); // 推导类型为int 左值
decltype(static_castint(i)); // 推导类型为int 将亡值
decltype(i); // 推导类型为int 右值
decltype(i); // 推导类型为int 左值
decltype(hello world); // 推导类型为const char()[12] 常量数组左值四、CV限定符
通常情况下decltype(e)所推导的类型会同步e的cv限定符cv限定符这里是指onst和volatile关键字
const int i 0;
decltype(i); // 推导类型为const int当e是未加括号的成员变量时父对象表达式的cv限定符会被忽略不能同步到推导结果
struct A {double x;
};
const A* a new A();
decltype(a-x); // 推导类型为double, const属性被忽略
decltype((a-x)); // 推导类型为const double, const属性不被忽略