欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

decltype,decltype(auto) (tcy)

程序员文章站 2024-03-23 10:31:58
...

一.decltype说明符  

                
1.1.语法:        
   decltype ( entity ) 实体      
   decltype ( expression )//返回 expression 表达式的类型-必须加括号       
        
1.2.用途: 
   1)在声明使用标准符号难以或无法声明的类型时使用
         (如与lambda相关的类型或依赖模板参数的类型)与auto一样用于进行编译时类型推导
   2)检查实体的声明类型或表达式的类型和值类别,函数返回值后置推导       
    
   3)auto只能用于赋值语句,decltype()可推导任意表达式类型,但是必须在()写全表达式
        故而引申出decltype(auto)例:decltype(auto) z =x+y == decltype(x + y) dest =x+y;  
        
1.3.说明:        
    1) decltype 仅“查询”表达式类型不会对表达式进行“求值”       
    2)auto声明一变量;decltype则可从变量或表达式中得到类型
 
    3)类型不必是完整的或具有可用的析构函数且可是抽象的
         该规则不适用子表达式:decltype(f(g()));  //g()必须具有完整的类型,但是f()不需要 

1.4.注意:
 1)如对象名称带有括号则将其视为普通的左值表达式
       因此decltype(x)和decltype((x))通常是不同的类型       
 2)字符串字面值常量是个左值,且是const左值,而非字符串字面值常量则是个右值        
 3)函数:       
      std::is_lvalue_reference<>::value ;//判断表达式是否为左值        
      std::is_rvalue_reference<>::value ;//判断表达式是否为右值  
        
1.5.推导规则:                 
 1)如参数是无括号(id-expression表达式或类成员访问表达式),则返回表达式实体的类型
       如没有这样实体,或参数指定是重载函数则程序格式错误               
       如参数是未括号id-expression命名结构化绑定,则返回引用类型(C++ 17)   
       如参数是未括号id-expression命名非类型模板参数,则返回模板参数类型C++ 20) 
  
 2)如expression是函数调用或重载操作符调用返回函数的返回数值的类型 

 3)如参数是表达式类型T,则 
       a)如表达式值类别是xvalue(亡值)则返回T&&; 
       b)如表达式值类别为lvalue(左值)则返回T&; 
       c)如表达式值类别为prvalue(纯右值)则返回T 
2.实例: 
实例1: 
 typename T::const_iterator it;
 decltype(T.begin()) it;
  
 typedef decltype(nullptr) nullptr_t;       //标准库中应用
 typedef decltype(sizeof(0)) size_t;
实例2:       
 #include <iostream>
 #include <assert.h>

 using namespace std;

 void foo(int x) {};
 void foo(char c1, char c2) {};              //重载函数        
 const bool bar(int x) { return true; };
 const bool& func(int x) { return  true; };

 struct Data { double d; }s;

 //返回类型后置语法
 template<typename T, typename U>
 auto add(T t, U u) -> decltype(t + u)  //返回类型取决于模板参数 
 {return t + u;}

 int main() {
  //规则一:推导为表达式类型
  int x = 1;
  decltype(x) z1 = x * 2;                      //int z1;    
  
  int arr[4] = { 0 }; 
  int* ptr = arr;
  decltype(ptr) z2 = &x;                      //int * z2; 标记符表达式 
  
  decltype(arr) z3 = { 0 };                   //int[4] 标记符表达式 int z3[4];
  
  const Data* p_s = &s;
  decltype(p_s->d) z4=0;                  //doubel z4 成员访问表达式 
  decltype((p_s->d)) z5=0;                //const double& z5(左值表达式)

  //规则二:推导为函数调用返回类型       
  //对于纯右值只有类类型可携带CV限定符其他一般忽略掉CV限定符       
  decltype(bar(1)) b1 = true;            //bool 因为函数返回的是纯右值       
  decltype(func(1)) b2 = true;          //const bool &       

  //decltype(foo(x)) y;                       //重载函数-编译错误       
  auto _mul = [](int a, int b) -> int {return a * b; };
  decltype(_mul) mul = _mul;        //lambda函数的类型是独特的和未命名 
  assert(mul(2, 3) == _mul(2, 3));
  assert(add(2, 3) == 5);

  //规则三:左值-推导为类型的引用       
  decltype((x))y1 = x;                    //int& - (x)是一个左值       
  decltype(true ? x : x) y2 = x;      //int&  条件表达式返回左值       
  decltype(++x) y3 = x;                //int&  ++i返回i的左值       
  decltype(arr[5]) y4 = x;              //int&  []操作返回左值       
  decltype(*ptr)y5 = x;                  //int&  *操作返回左值       
  decltype("hello")y6 = "hello";     //const char(&)[6] 字符串字面常量为const左值       

  //右值,则推导为本类型       
  decltype(1) y7 = 10;                  //int        
  decltype(x++) y8 = x;                //int x++返回右值          
 }

二. decltype(auto)占位符类型说明符

1.1.用途: 
 1)对于变量,指定将从其初始值设定项自动推断出要声明的变量的类型 C++11  
 2)对于函数,指定将从其return语句推导返回类型C++14  
 3)对于非类型模板参数,指定将从参数推导出类型C++17 template<auto I> struct A; 
          
1.2.格式:    
 auto                                          -1 (since C++11) 存储类       
 decltype(auto)                          -2 (since C++14)        
 type-constraint auto                 -3 (since C++20)        
 type-constraint decltype(auto) -4 (since C++20)        
 
 说明:
 1)type-constraint -可选,类型约束,后可跟跟<>中模板参数列表
      占位符auto可附带修饰符(如const or & )将参与类型推演
    
 2)1,3使用模板参数推导规则推导类型  
 3)2,4类型是decltype(expr),其中expr是初始值设定项 
          
1.3.使用:  

1)指定变量类型:
   auto x = expr;//从初始化程序推导
      
   //decltype(auto)从函数调用模板参数推导变量类型
   template<class U> void f(const U& u)
   const auto& i = expr;
   f(expr);

   //auto&& 用于ranged for循环(基于左值或右值)
              
   //如用占位符类型说明符声明多个变量,则推导类型必须匹配
   auto i = 0, d = 0.0;   //格式错误  
   auto i = 0, *p = &i;   //格式正确,auto可以推导为整型
   auto f() -> int, i = 0; //声明中混合变量和函数错误 
       
2)type-id  x;类型从初始化程序推导
   T x;类型从初始化程序(小括号)或初始化列表推导(大括号)
   
3)Lambda表达式或函数参数为auto(since C++20)
   [](auto&&){};                  //通用lambda
   void f(auto);                   //函数声明引入了一缩写函数模板 
 
   //auto 说明符可与后跟尾随返回类型的函数声明符一起使用          
   auto (*p)() -> int;           //将p声明为返回int   
   auto (*q)() -> auto = p; //将q声明为指向返回T的函数的指针-从p的类型推导出T
 
4)非类型模板参数
   template<auto I> struct A; 

说明:  
   auto说明符也可以在结构化绑定声明中使用  
   auto关键字也可以在嵌套名称说明符中使用

2.实例:                   
 #include <iostream>
 #include <assert.h> 

 using namespace std; 

 #include <iostream>          
 #include <utility>           

 template<class T, class U>
 auto add(T t, U u) { return t + u; }                     //返回类型是operator+(T, U)的类型   

 // 函数调用必须使用decltype(Auto),以防它调用的函数通过引用返回  
 template<class F, class... Args>
 decltype(auto) PerfectForward(F fun, Args&&... args)
 { return fun(std::forward<Args>(args)...);} 

 template<auto n>                                             // C++17 auto 参数声明  
 auto f() -> std::pair<decltype(n), decltype(n)> // auto不支持从init-list推断          
 { return { n, n };} 

 int main() {
  auto x = 1 + 2;
  auto y = add(1, 1.2);
  static_assert(std::is_same_v<decltype(x), int>);
  static_assert(std::is_same_v<decltype(y), double>); 

  auto z1 = x;                          // 类型c0是int,持有a的副本         
  decltype(auto) z2 = x;          // 类型z2是int,持有x的x副本          
  decltype(auto) z3 = (x);        // type of z3 is int&, an alias of x          < /FONT > 

  ++z3; assert(z3 == 4);< /FONT > 

  auto [v, w] = f<0>();            //结构化绑定声明          < /FONT > 

  auto d = { 1, 2 };                  // OK: type of d is std::initializer_list<int>          
  auto n = { 5 };                      // OK: type of n is std::initializer_list<int>          
         
  auto m{1};                           // auto 只能从单个值initializer_list<int>中推导 auto e{1, 2};错误          
  
  //decltype(auto) z = { 1, 2 } // Error: {1, 2} is not an expression          
      
  // auto通常用于未命名的类型,例如lambda表达式的类型  
  auto lambda = [](int x) { return x + 3; };< /FONT > 

  //  auto int x;                      // valid C++98, error as of C++11          
  //  auto x;                           // valid C, error in C++          
 }       

 

相关标签: C/C++