C++关键字decltype

decltype引入的原因之一是在函数模板中遇到如下情形:

template <typename T1, typename T2>
void foo(T1 a, T2 b)
{
    ?type? tmp = a + b;
}

此时,tmp类型该定义为哪种呢?我们知道基础数据类型相加时会自动进行类型提升,直接用T1或者T2都是不合适的。此时就需要使用新的关键字decltype

template <typename T1, typename T2>
void foo(T1 a, T2 b)
{
    decltype(a + b) tmp = a + b;
}

由编译器自己在编译过程中推导,当然也可以用auto代替。decltype关键字的作用是获取提供给它的参数的数据类型。可以是变量,表达式,函数调用等。使用decltype的格式如下:

decltype(expression) var;

确定decltype推导出来的类型按如下步骤:

  • 第一步:如果expression是一个没有额外括号扩起来的变量,则var的类型和该变量类型相同,包括cv限定符;

    int x;
    int y;
    int z[10];
    int &rx = x;
    const int *pi;
    
    decltype(x) a;      //int类型
    decltype(rx) b = y; //int &类型
    decltype(pi) c;     //const int* 类型
    decltype(z) d;      //int[10]类型
    
    //除了一般变量,也可以是函数指针(起始也是一般变量,就是指针而已)
    int foo(){return 0;}
    decltype(foo) myFoo;  //int(*)()类型,注意这里表达式是函数名
    
  • 第二步:如果expression是函数调用,则var的类型和函数返回值一样;

    int foo(){return 0;}
    decltype(foo()) fooRet;	 //int类型
    

    处理函数调用时,它的原理是直接查看函数声明中的返回值类型,所以甚至都不需要看到函数实现:

    int foo();
    int main()
    {
        decltype(foo()) var;	//int类型
        return 0;
    }
    
  • 第三步:如果expression是用额外括号括起来的左值,那么var的类型就是对应类型的引用,包括cv限定符;

    int x;
    int y;
    const int a = 1;
    const int b = 2;
    decltype((x)) ry = y;	//int &类型,如果不做赋值操作,会提示错误
    decltype((a)) rb = b;	//const int &类型,如果不做赋值操作,会提示错误
    rb = 1;	//报错,因为rb是const int &类型
    
  • 第四步:如果expression是表达式,则var类型与其类型一样:

    int x = 1;
    int &y = x;
    decltype(x + 1) a;     //int类型
    decltype(x + y) b;     //int类型
    decltype(3) c;         //int类型
    decltype(4L) d;        //long类型
    decltype(5.0f) e;      //float类型
    
    int foo();
    decltype(foo() + 3) f; //int类型
    

    有一个比较特殊的类型void类型,我们知道void类型用在函数声明上,主要给函数返回值或者参数用。所以有以下变态写法:

    void foo();
    
    decltype(foo()) bar(decltype(foo()))
    {
    }
    

    不过这种用法好像毫无意义。

还有一种情况,如下:

template <typename T1, typename T2>
?type? Add(T1 a, T2 b)
{
    return a + b;
}

如果定义了一个模板函数,将两个不同类型的变量相加,并且返回他们的和。那此时返回值类型该是那种?或许我可以加入第三个类型解决:

template <typename T0, typename T1, typename T2>
T0 Add(T1 a, T2 b)
{
    return a + b;
}

如果调用如下:

char a = 1;
short b = 2;
int sum;
sum = Add<int, char, short>(a, b);
sum = Add(a, b);	//不支持类型推导,提示无法推导类型T0

好像也没啥问题,但是需要我们知道不同类型相加时类型提升的规则,这无疑是很麻烦的。于是decltype被引入了,它结合auto关键字使用:

template <typename T1, typename T2>
auto Add(T1 a, T2 b) -> decltype(a + b)
{
    return a + b;
}
auto function(args...) -> type

这种函数声明时,以auto作为返回值类型,真实类型放后面通过->连接的语法称之为后置返回类型。其中auto表示占位符,表示后置返回类型提供的类型,这是C++11给auto新增的一种作用。这种用法也可以用于一般函数的定义。

auto foo() -> int
{
}
posted @ 2024-06-28 15:17  thammer  阅读(2)  评论(0编辑  收藏  举报