1_auto类型推导(深入应用C++11:代码优化与工程级应用)

1. auto回顾

  在深入学习auto前,本人已经了解了auto的基本用法,对于简单类型推导能够清晰理解.如:

int i = 0;
auto ii = 1;    // auto被推导为int
auto iii = i;   // auto被推导为int

  本次学习是为了加深细节理解,如:auto 与指针\引用\cv限定符一起使用时的推导结果.

  回顾下简单类型的推导及使用auto时需要注意哪些.

int int_type = 1;               //int       auto被推导为int
float float_type = 1.0;         //float     auto被推导为float
const int const_int_type = 1;   //int const auto被推导为int
auto auto_int = 1;              //int       auto被推导为int
auto auto_double = 1.0;         //double    auto被推导为double

auto x= 5;                      //int       auto被推导为int
auto pi = new auto(1);          //int*      auto被推导为int*
const auto *v = &x, u=6;        //v:int const *    auto 被推导为 int
                                //u:int const      auto 被推导为 int
static auto y = 0.0;            //double           auto被推导为double
auto int r;         // error:two or more data types in declaration of 'r' 
int int r;          // error:two or more data types in declaration of 'r'
auto s;             // error:declaration of 'auto s' has no initializer

需要注意的是:

const auto *v = &x, u=6;
//在推导的时候u必须赋值,且所赋的值不能让auto推导产生二义性,否则无法通过编译
/**u 必须要赋值,否则就等价 const auto u;// error
    * 如:const auto *v = &x, u;
    * error: declaration of variable 'u' with deduced type 'const auto' requires an initializer
    */
/**并且u的初始化不能是编译器推导产生二义性,否则编译失败.
    * 如:const auto *v = &x, u =6.0;
    * error: 'auto' deduced as 'int' in declaration of 'v' and deduced as 'double' in declaration of 'u'
    */

  由上面的例子可以看出来,auto并不能代表一个实际的类型声明(如s的编译错误),只是一个类型声明的"占位符".

  使用auto声明的变量必须马上初始化,以上编译器推断出它的实际类型,并在编译时将auto占位符替换为真正的类型.

2. auto推导规则

int x = 0;
auto * a = &x;          // int* auto被推导为int
auto   b = &x;          // int* auto被推导为int*
auto & c = x;           // int& auto被推导为int
auto   d = c;           // int  auto被推导为int

const auto e = x;       // int const   auto被推导为int
auto   f = e;           // int         auto被推导为int
const auto & g = x;     // int const & auto被推导为int
auto & h = g;           // int const & auto被推导为int const

const auto * gg = &x;   // int const * auto被推导为int
auto * hh = gg;         // int const * auto被推导为int const

  由上面的例子可以看出:

  • a和c的推导结果是很显然的, auto在编译的时候被替换为int, 因此a和c分别被推导为int*和int&.
  • b的推导结果说明, 其实auto不声明为指针, 也可以推导出指针类型.
  • d的推导结果说明, 当表达式是一个引用类型时, auto会把引用类型抛弃, 直接推导成原始类型int.
  • e的推导结果说明, 当表达式带有const(实际上volatile也会得到同样的结果)属性时, auto会把const属性抛弃掉, 推导成non-const类型int.
  • g/h的推导说明, 当auto和引用(换成指针在这里也将得到同样的结果, 如:用gg推导hh)结合时, auto的推导将保留表达式的const属性.

通过上面一系列示例, 可以得到下面两条规则:

  1. 当不声明为指针或引用时, auto的推导结果和初始化表达式抛弃引用和cv限定符后类型一致.
  2. 当声明为指针或引用时, auto的推导结果将保持初始化表达式的cv属性.

3. auto与函数模板

  auto的推导和函数模板参数的自动推导有相似之处.下面模板参数的自动推导和auto的类型是一致的:

template<typename T> void func(T x){}
template<typename T> void func(T * x){}
template<typename T> void func(T & x){}

template<typename T> void c_func(const T x){}
template<typename T> void c_func(const T * x){}
template<typename T> void c_func(const T & x){}

func(x);        // func(T x)   参数被推导为int T被推导为int
func(&x);       // func(T * x) 参数被推导为int*  T被推导为int
func(x);        // func(T & x) 参数被推导为in&   T被推导为int

func(e);        // func(T x)   参数被推导为int T被推导为int
func(gg);       // func(T * x) 参数被推导为int const *  T被推导为int const
func(h);        // func(T & x) 参数被推导为int const &  T被推导为int const

c_func(e);      // c_func(const T x)   参数被推导为int const    T被推导为int
c_func(gg);     // c_func(const T * x) 参数被推导为int const *  T被推导为int
c_func(h);      // c_func(const T & x) 参数被推导为int const &  T被推导为int

注意:(T x)版本的模板和(T & x)的模板在验证时只能使其中一个版本生效, 否则会使推导产生二义性导致无法编译. (const T x)与(const T & x)也是如此.

auto不能用作函数的参数. 这点很容易理解, 如果auto可以用作函数的参数, 相当于在编译时就需要对该函数定义所有可能参数的类型.

 void func_auto(auto a){ // error: 'auto' not allowed in function prototype

}

// 相当于需要定义一下函数
void func_auto(char a){}
void func_auto(unsigned char a){}
void func_auto(short a){}
void func_auto(unsigned short a){}
void func_auto(int a){}
void func_auto(unsigned int a){}
void func_auto(float a){}
void func_auto(unsigned float a){}
void func_auto(double a){}
void func_auto(unsigned double a){}
void func_auto(long a){}
void func_auto(unsigned long a){}
void func_auto(long long a){}
void func_auto(unsigned long long a){}
...
...
...

4. auto的限制

  上一小节结尾已经梳理了auto不可以作为函数参数的自动推导.那还有哪些情况下无法使用auto自动推导呢?

auto func_ra(){ // error: 'auto' return without trailing return type; deduced return types are a C++14 extension
    return 0;
}

auto func_ra(int a,int b)->decltype (a+b){ // OK
    return a+b;
}

class A {
public:
    auto a =0;              // error: 'auto' not allowed in non-static class member
    static const auto ai2 = 0;
//    static const auto af2 = 0.0;    // error: in-class initializer for static data member of type 'const double' requires 'constexpr' specifier

    static int x;           // static const 的整形或者枚举成员才可以在类内初始化.
                            // 否则就只能在类内声明,在类外通过A::的形式初始化
    static int y = 0;       // error: non-const static data member must be initialized out of line
    static double d = 0.0;  // error: non-const static data member must be initialized out of line
    static float f = 0.0;   // error: non-const static data member must be initialized out of line
    static char c = '0';    // error: non-const static data member must be initialized out of line

    static const int c_i = 0;
    static const double c_d = 0.0;  // error: in-class initializer for static data member of type 'const float' requires 'constexpr' specifier note: add 'constexpr'
    static const float c_f = 0.0;   // error: in-class initializer for static data member of type 'const float' requires 'constexpr' specifier note: add 'constexpr'
    static const char c_c = '0';
};
int A::x = 0;

template <typename T>
class B{};

int array[4] = {0};
auto aarray = a;
auto array2[4] = array; // error: 'array2' declared as array of 'auto'
auto array3[4] = {0};   // error: 'array3' declared as array of 'auto'

B<int> bb;
B<auto> a_bb = bb;  // error: 'auto' not allowed in template argument

通过测试可以得到一下规则:

  • auto只能static const 整形或者枚举 成员
  • auto无法作为模板的参数类型传入
  • auto无法推导数组的类型
  • auto无法直接作为函数的返回值进行自动推导(在c++14后是可以的,c++11不允许), 但是可以和decltype结合使用.
  • auto无法直接作为模板函数的返回值使用, 但是可以和decltype结合使用. 后面介绍decltype时会具体验证.

posted on 2022-07-26 08:38  dogpi  阅读(163)  评论(0编辑  收藏  举报

导航