ri# RTTI
Run-Time Type Information,运行时类型信息。
RTTI
这种情况,一般是运行时的类型转换的,一般是和类型转换配合使用,给出代码实例:
#include <iostream>
class Base {
public:
virtual void foo() {
std::cout << "base derived\n";
}
};
class Derived: public Base {
public:
void foo() override {
std::cout << "derived foo\n";
}
};
int main() {
Base* bptr = dynamic_cast<Base*>(new Derived());
bptr->foo();
}
bptr
虽然是Base*
类型,但是 RTTI 让bptr
成为了Derived
类型。
decltype
RTTI 机制说明了C++会有运行时的类型。而在模板编程中,我们传入的类型必须是固定的,但是 RTTI 无法满足这个要求,因为RTTI 的类型必须得运行的时候确定。为了解决这种推导的问题,C++引入auto
&decltype
机制。auto
不再赘述,这里主要说明decltype
如何在编译期间确定 RTTI。
decltype(expr)
是最基本的用法,即expr
如果是普通类型,那么直接返回原样的类型;如果是表达式,则返回表达式计算结果的类型。举个例子:
#include <iostream>
int foo() {
std::cout << "foo\n";
return 0;
}
int main() {
int a = 10;
decltype(a) b = a;
decltype(foo()) c = a;
// 注意 lambda 无法直接推导,必须要赋值,然后执行表达式才可以
auto F = []() { return 0; };
decltype(F()) d = a;
std::cout << a << ", " << b << ", " << c << ", " << d << std::endl;
return 0;
}
上面的表达式虽然调用了执行的符号,但是不会执行,只用用于获取 RTTI
decltype(e)
有几个规则:
- 如果e是一个没有带括号的标记符表达式或者类成员访问表达式,那么的decltype(e)就是e所命名的实体的类型。此外,如果e是一个被重载的函数,则会导致编译错误。
- 否则 ,假设e的类型是T,如果e是一个将亡值,那么decltype(e)为T&&
- 否则,假设e的类型是T,如果e是一个左值,那么decltype(e)为T&。
- 否则,假设e的类型是T,则decltype(e)为T。
进一步拓展一个例子:
#include <iostream>
struct Foo {
int a{10};
int foo() {
return 0;
}
};
int main() {
int a = 10;
decltype(a) b = 10;
decltype((b)) c = b; // (1)
c = 20;
std::cout << "b = " << b << ", c = " << c << std::endl;
decltype(Foo().a) d = 30;
decltype((Foo().a)) e = 40; // (2)
std::cout << "d = " << d << ", e = " << e << std::endl;
decltype(Foo().foo()) f = 100; // (3)
std::cout << "f = " << f << std::endl;
return 0;
}
/*
b = 20, c = 20
d = 30, e = 40
f = 100
*/
(1)中,c 表示引用类型, (2)中的 e 表示右值类型,(3)中的 f 也是左值,注意使用方式,Foo::foo
不会真正执行调用。
decltype(auto)
的使用方式,给出一个最典型的应用:
template<typename Container, typename Index>
decltype(auto)authAndAccess(Container&& c, Index i){
authenticateUser();
return std::forward<Container>(c)[i];
}
返回值如果是左值,那么就作为左值;右值当做右值。
declval
declval
把所有的类型转换成左值引用,一般和decltype
配合使用,用于转换那些没有构造函数的类型,给个代码实例:
#include <iostream>
#include <utility>
struct Foo {
Foo() = delete;
int foo() {
return 0;
}
};
int main() {
decltype(std::declval<Foo>().foo()) a = 10;
std::cout << a << std::endl;
return 0;
}
Foo
由于没有构造函数,所有不能直接decltype(Foo().foo())
,只能和std::declval
配合使用,std::declval<Foo>()
返回一个Foo&
参考文档
https://www.cnblogs.com/QG-whz/p/4952980.html
https://zsmj2017.tech/post/77bd3be8.html