[C/C++11]_[初级]_[关于auto和decltype说明符的简单介绍]

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/infoworld/article/details/79992063

场景

1.auto,decltype说明符是C++11新增的类型推导(deduction)说明符, 他们都有各自的使用场景, 作用相互补充.

2.搞清楚它们的使用规则对用好这两个说明符能让你用的更加正确; 还有你会发现C++原来那么复杂的其中一个原因就是它的说明符根据表达式,符号(*,&,…)使用情况,环境相当复杂多变,要记住这些区别非常不容易, 单单是这些符号的组合就让人头疼, 做Java的或C的已经相当幸福了, 至少目前我的水平也觉得C++的说明符, 符号的组合实在太多了.

3.要熟练使用还是得搞清楚lvalue,rvalue,xvalue, lvalue expression, rvalue expression, xvalue expression.

说明

auto

语法

auto variable initializer
auto function -> return type

1.第一种是变量类型说明符, 在编译时根据初始化器的类型来推导variable的实际类型. 可以使用 auto推导的实际类型, 或者auto& 来表示引用类型, auto&& 来表示一个左值或右值引用. 其中 auto 还可以用与lambda表达式的声明.

auto i = 0, *p = &i;
auto lambda = [](int x) { return x + 3; };

2.第二种声明一个带->拖尾返回符号的函数. auto不会执行自动函数探测(detect), 仅仅是作为语法的一部分.

template<typename T, typename U>
auto add(T t, U u) -> decltype(t + u) // return type depends on template parameters
                                      // return type can be deduced since C++14
{
    return t+u;
}

decltype

语法

decltype ( entity ) (1) (since C++11)
decltype ( expression ) (2) (since C++11)

1.第一种情况, 推导这个类型,可以说是变量的类型.

int i  = 0;
decltype(i) j;
decltype((i)) j1 = j; // 带括号推导出引用类型.

auto my_hHash = [](HCRYPTHASH* hHash){CryptDestroyHash(*hHash);};
std::unique_ptr<HCRYPTHASH,decltype(my_hHash)> p2(&hHash,my_hHash);

2.第二种情况是表达式, 注意和auto不同的是它支持表达式;
– 如果表达式的值类型是 xvalue(过期值), 那么decltype 推导(yields)出T&&
– 如果表达式的值类型是 lvalue(左值), 那么decltype 推导(yields)出T&
– 如果表达式的值类型是 prvalue(纯右值), 那么decltype 推导(yields)出T


// 值类型是xvalue.
int i = 2;
decltype(std::move(i)) a1 = std::move(2);

// 值类型是左值
int j = 2;
decltype(i = 3) j3 = j;

// 值类型是纯右值
decltype(a->x) y;     
decltype((a->x)) z = y;

template<typename T, typename U>
auto add(T t, U u) -> decltype(t + u)

{
    return t+u;
}

例子

#include <regex>
#include <assert.h>
#include <iostream>
#include <iterator>
#include <set>
#include <typeinfO>

struct A { double x; };
const A* a;

decltype(a->x) y;       // type of y is double (declared type)
decltype((a->x)) z = y; // type of z is const double& (lvalue expression)

template<typename T, typename U>
auto add(T t, U u) -> decltype(t + u) // return type depends on template parameters
                                      // return type can be deduced since C++14
{
    return t+u;
}

// https://stackoverflow.com/questions/28621844/is-there-a-typeid-for-references
template <class T>
std::string
type_name()
{
    typedef typename std::remove_reference<T>::type TR;
    std::unique_ptr<char, void(*)(void*)> own
           (
#ifndef _MSC_VER
                abi::__cxa_demangle(typeid(TR).name(), nullptr,
                                           nullptr, nullptr),
#else
                nullptr,
#endif
                std::free
           );
    std::string r = own != nullptr ? own.get() : typeid(TR).name();
    if (std::is_const<TR>::value)
        r += " const";
    if (std::is_volatile<TR>::value)
        r += " volatile";
    if (std::is_lvalue_reference<T>::value)
        r += "&";
    else if (std::is_rvalue_reference<T>::value)
        r += "&&";
    return r;
}

void TestDecltype() 
{
    int i = 33;
    decltype(i) j = i * 2;

    std::cout << "i = " << i << ", "
              << "j = " << j << '\n';

    auto f = [](int a, int b) -> decltype(a + b)
    {
        return a * b;
    };

    decltype(f) g = f; // the type of a lambda function is unique and unnamed
    i = f(2, 2);
    j = g(3, 3);

    decltype((j)) j1 = j;
    j1 = 100;
    auto& j2 = j1;

    auto i2 = add(10,2);

    decltype(i = 3) j3 = j;

    decltype(std::move(i)) a1 = std::move(2);

    std::cout << "i = " << i << ", "
              << "j1 = " << j1 <<  ", "
              << "j2 = " << j2 <<  ", "
              << "i2 = " << i2 <<  ", "
              << "j3 type = " << typeid(j3).raw_name()   <<  ", "
              << "j3 = " << j3 <<  ", "
              << "j3 type = " << type_name<decltype(j3)>() <<  ", "
              << "decltype(std::move(a) = " << type_name<decltype(std::move(i))>() <<  ", "
              << "j = " << j << '\n';
}

输出:

i = 33, j = 66
i = 4, j1 = 100, j2 = 100, i2 = 12, j3 type = .H, j3 = 100, j3 type = int&, decl
type(std::move(a) = int&&, j = 100

参考

C++11_初级_左值引用声明和右值引用声明
C/C++不常见语法特性初级左值-右值-lvalue-rvalue
auto specifier (since C++11)
decltype specifier (since C++11)
is-there-a-typeid-for-references

猜你喜欢

转载自blog.csdn.net/infoworld/article/details/79992063