当前位置: 代码网 > it编程>编程语言>C/C++ > C++11范围for初始化列表auto decltype详解

C++11范围for初始化列表auto decltype详解

2025年07月28日 C/C++ 我要评论
c++11新特性1. 自动类型推导auto`在c++98中auto是一个存储类型的说明符,表明变量是局部自动存储类型,但是局部域中定义局部的变量默认就是自动存储类型,所以auto就没什么价值了。c++

c++11新特性

1. 自动类型推导auto

`在c++98中auto是一个存储类型的说明符,表明变量是局部自动存储类型,但是局部域中定义局部的变量默认就是自动存储类型,所以auto就没什么价值了。

c++11中废弃auto原来的用法,将其用于实现自动类型腿断。这样要求必须进行显示初始化,让编译器将定义对象的类型设置为初始化值的类型。

1.1 基本语法

auto i = 42;        // i 是 int
auto d = 3.14;      // d 是 double
auto s = "hello";   // s 是 const char*
auto v = {1, 2, 3}; // v 是 std::initializer_list<int>
const auto ci = i;     // const int
auto& ri = i;          // int&

2. decltype

关键字decltype将变量的类型声明为表达式指定的类型。

// decltype 可以推导出参数类型,并进行传递
vector<decltype(it)>v1;

decltypeauto方便的一点是decltype无需显式实例化,也就是单纯定义也行decltype还可以作为模板参数传递,而auto不行。

3. 列表初始化

​ 在 c++11 中,初始化列表(使用花括号 {})为内置类型和自定义类型的初始化提供了统一、安全的语法。下面一一列举。

  • 初始化列表 {} 是 c++11后 的推荐方式,提供类型安全语法统一性
  • 构造函数初始化 () 保留传统行为,但在某些场景(如 stl 容器)可能产生歧义。

3.1 内置类型

int main(){
    int a{ 5 };     // 直接初始化
    int b = { 10 }; // 拷贝初始化
    char g{ 'a' };  // 正确,但不能超过char范围

    int* ptr1{};   // 初始化为空指针
    int* ptr2{ &a }; // 指向变量a

    int arr1[]{ 1, 2, 3 };  // 自动推导大小
    int arr2[5]{ 1, 2, 3 }; // 部分初始化,剩余元素为0
    char str[]{ "hello" };  // 字符数组

    std::cout << "ptr1: " << ptr1 << "\n"
        << "ptr2: " << ptr2 << "\n"
        << "str: " << str << std::endl;
    return 0;
}

其实就是当内置类型使用 { }初始化时,实际上是在调用它的构造函数进行构造这就不奇怪了,无非就是让内置类型将 { } 也看做一种特殊的构造:构造+赋值 优化为直接构造我们可以通过一个简单的datw类来体现这一现象。

class date {
public:
    date(int y,int m,int d):_year(y),_month(m),_day(d){}
private:
    int _year;
    int _month;
    int _day;
};
int main(){
    date d1 = { 0,1,1 };
    return 0;
}

此时可以直接通过列表初始化{}初始化这个类。在c++11中允许省略=符号,编译无报错,使其与拷贝构造函数一样。使用关键字·explicit·可以避免编译器隐式转换。

这样编译器无法优化,便无法对d1进行构造,自然无法完成赋值。d2相当于直接拷贝构造函数。

即对于内置类型来说,列表初始化 { } 实际上就相当于调用了内置类型的构造函数,构造出来一个对象。

3.2 自定义类型

c++11之前对于自定义类型初始化比较复杂,例如vector需要循环插入,在c++11时使用初始化列表对于自定义类型的数据操作更加方便。

3.2.1 初始化列表赋值底层

对于stl容器:

stl容器(如 vectormapset 等)重载了 operator= 以支持 std::initializer_list,因此,可以直接用 {} 赋值:

std::vector<int>& operator=(std::initializer_list<int> il);

map<string, string> dict = { {"sort", "排序"}, {"insert", "插入"} };
std::vector<int> v;
v = {1, 2, 3};  // 调用 operator=(initializer_list<int>)

对于自定义类

如果类定义了 operator= 接受 std::initializer_list,则可以使用 {} 赋值:让模拟实现的vector也支持{}初始化和赋值…

template <class t>
        class vector{
        public:
            typedef t *iterator;
            vector(initializer_list<t> l){
                _start = new t[l.size()];
                _finish = _start + l.size();
                _endofstorage = _start + l.size();
                iterator vit = _start;
                typename initializer_list<t>::iterator lit = l.begin();
                while (lit != l.end()){
                    *vit++ = *lit++;
                }
            }
            vector<t> &operator=(initializer_list<t> l){
                vector<t> tmp(l);
                std::swap(_start, tmp._start);
                std::swap(_finish, tmp._finish);
                std::swap(_endofstorage, tmp._endofstorage);
                return *this;
            }
        private:
            iterator _start;
            iterator _finish;
            iterator _endofstorage;
        };
  • 同时提供普通构造函数和 initializer_list 构造函数时,注意优先级差异。

4. 范围 for

其为c++11引入的一种简化容器遍历的语法,它使遍历序列容器(如数组、vector、list 等)变得更加简洁直观。

基本语法:

for (类型 变量名 : 目标序列) {
    // 循环体
}

如果需要修改容器中的元素,需要使用引用,这样能够避免发生数据拷贝影响效率。同时使用const修饰能够避免修改原始对象。

std::vector<std::string> words = {"aaaa", "bbbb", "cccc"};
for (const auto& word : words) {//使用 & 避免拷贝,使用const避免原始数据被修改
    std::cout << word << " ";
}
// 输出:aaaa bbbb cccc

5. 智能指针

bbb", “cccc”};
for (const auto& word : words) {//使用 & 避免拷贝,使用const避免原始数据被修改
std::cout << word << " ";
}
// 输出:aaaa bbbb cccc

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com