Item2 理解auto 的类型推导

auto 的类型推导与template 的类型推导类似,主要的区别在于对于 std::initialize_list 的区别。 在这个子项中的类型推导我们用到了boost 的1.67的版本。

具体的代码如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include  <iostream>
#include  <typeinfo>
#include  <boost/type_index.hpp>

void func(int,double)
{
}
int main(int argc,char * argv[])
{
    using boost::typeindex::type_id_with_cvr;
    //Case1:type specifier is a pointer or a reference but not a universal reference.
    auto x = 27;
    const auto cx = x;
    const auto& crx = x;
    auto& rx = x;

    std::cout  << "x Type is " << type_id_with_cvr<decltype(x)>().pretty_name() << std::endl;
    std::cout  << "cx Type is " << type_id_with_cvr<decltype(cx)>().pretty_name() << std::endl;
    std::cout  << "crx Type is " << type_id_with_cvr<decltype(crx)>().pretty_name() << std::endl;
    std::cout  << "rx Type is " << type_id_with_cvr<decltype(rx)>().pretty_name()  <<std::endl;

    auto&& uref1 = x;
    auto&& uref2 = cx;
    auto&& uref3 = rx;

    std::cout  << "uref1 Type is " << type_id_with_cvr<decltype(uref1)>().pretty_name() << std::endl;
    std::cout  << "uref2 Type is " << type_id_with_cvr<decltype(uref2)>().pretty_name() << std::endl;
    std::cout  << "uref3 Type is " << type_id_with_cvr<decltype(uref3)>().pretty_name() << std::endl;

    const char name[]="Hello Dennis";
    auto arr1 = name;
    auto& arr2 = name;

    std::cout  << "name Type is " << type_id_with_cvr<decltype(name)>().pretty_name() << std::endl;
    std::cout  << "arr1 Type is " << type_id_with_cvr <decltype(arr1)>().pretty_name() << std::endl;
    std::cout <<  "arr2 Type is " << type_id_with_cvr<decltype(arr2)>().pretty_name() << std::endl;

    auto func1 = func;
    auto& func2 = func;

    auto lamdaFunc = []()->void {return;};

    std::cout <<  "func1 Type is "  <<type_id_with_cvr<decltype(func)>().pretty_name() << std::endl;
    std::cout  << "func1 Type is " << type_id_with_cvr<decltype(func1)>().pretty_name() << std::endl;
    std::cout <<  "func2 Type is "  <<type_id_with_cvr<decltype(func2)>().pretty_name() << std::endl;
    std::cout  << "lamdaFunc Type is "<<  type_id_with_cvr<decltype(lamdaFunc)>().pretty_name() << std::endl;

    int x1 = 27;
    int x2(27);
    int x3={27};
    int x4{27};

    std::cout  << "x1 Type is " << type_id_with_cvr<decltype(x1)>().pretty_name()  <<std::endl;
    std::cout  << "x2 Type is " << type_id_with_cvr<decltype(x2)>().pretty_name()  <<std::endl;
    std::cout <<  "x3 Type is " << type_id_with_cvr<decltype(x3)>().pretty_name() << std::endl;
    std::cout   <<"x4 Type is "<<  type_id_with_cvr<decltype(x4)>().pretty_name() << std::endl;

    auto ax1 = 27;
    auto ax2(27);
    auto ax3={27};
    auto ax4{27};

    std::cout  << "ax1 Type is " << type_id_with_cvr<decltype(ax1)>().pretty_name() << std::endl;
    std::cout <<  "ax2 Type is " << type_id_with_cvr<decltype(ax2)>().pretty_name() << std::endl;
    std::cout <<  "ax3 Type is " << type_id_with_cvr<decltype(ax3)>().pretty_name() << std::endl;
    std::cout  <<"ax4 Type is "  <<type_id_with_cvr<decltype(ax4)>().pretty_name() << std::endl;

    return 0;
}

程序的输出如下: 使用 clang6.0 编译。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
x Type is int
cx Type is int const
crx Type is int const&
rx Type is int&

uref1 Type is int&
uref2 Type is int const&
uref3 Type is int&

name Type is char const [13]
arr1 Type is char const*
arr2 Type is char const (&) [13]

func1 Type is void (int, double)
func1 Type is void (*)(int, double)
func2 Type is void (&)(int, double)
lamdaFunc Type is main::$_0

x1 Type is int
x2 Type is int
x3 Type is int
x4 Type is int

ax1 Type is int
ax2 Type is int
ax3 Type is std::initializer_list int>
ax4 Type is int

两者的区别主要在于 std::initializer_list
例如:

1
2
3
4
5
//代码1
template<typename T>
void func(T param)
{
}

对于形如代码1的代码,是不可以这样调用的func({1,2,3});

如果要实现上面的调用方式,需要进行如下的实现

1
2
template <typename T>
void func(std::initailizer_list T> param);

总结:

  1. auto 的类型推导和template 类似,区别在于auto 默认由花括号{} 的初始化代表一个 std::initializer_list ,而模板的类型推导不是这样的。
  2. 用在函数返回值的auto 实现的是模板类型推导,而不是auto类型推导。