本文记录C++11的返回值类型后置,范围for,nullptr, lambda表达式。

第二章 通用性增强

2.3 返回值类型后置 (追踪返回类型)

在不使用返回值后置的情况下,返回值类型需要手工指定。T和U根据实参可自动推导,在程序中可以不写。

    template<typename R,typename T,typename U>
    R add(T t, U u)
    {
        return t + u;
    }
    void test()
    {
        int x = 321;
        double y = 2.2;

        auto z = add<double, int, double>(x, y);
        cout << "z = " << z << endl;
        // z = 323.2

        auto z2 = add<decltype(x + y)>(x, y);
        cout << "z2 = " << z2 << endl;
        // z = 323.2
    }

使用返回类型后置,可以减少一个参数:

    template<typename T, typename U>
    auto add3(T t, U u)-> decltype(t + u) // 这种方式不可,因为t + u还未定义
    {
        return t + u;
    }

    void test2()
    {
        int x = 321;
        double y = 2.2;

        auto z = add3<int, double>(x, y);
        cout << "z = " << z << endl;
        // z = 323.2

        auto z2 = add3(x, y);
        cout << "z2 = " << z2 << endl;
        // z = 323.2
    }

2.4 范围for

C++11 引入了范围for循环,书写方便。

    void test()
    {
        // 迭代器的循环
        vector<int> vec{ 3,4,5,6 };
        for (vector<int>::iterator it = vec.begin(); it != vec.end(); ++it)
        {
            cout << *it << " ";
        }
        cout << endl;

        // 使用auto
        for (auto it = vec.begin(); it != vec.end(); ++it)
        {
            cout << *it << " ";
        }
        cout << endl;

        // 范围for : value是 vec中复制,可以使用引用
        for (auto value : vec)
        {
            cout << value << " ";
        }
        cout << endl;

        // 使用引用,可以修改 vec , 如果不修改,加上const,表示只读
        for (const auto& value : vec)
        {
            cout << value << " ";
        }
        // 3 4 5 6 
    }

2.5 指针空值类型 nullptr(类型转换运算符)

C++11之前都是NULL对指针初始化。 NULL实现原理如下:

#ifndef NULL
    #ifdef __cplusplus      // 如果源码是C++程序,NULL 是0
        #define NULL 0
    #else
        #define NULL ((void *)0)   // 其他如果是C程序,对0进行 void*转换为指针
    #endif
#endif

为何这样转呢?因为C++中,void 类型无法隐士转换为其他类型指针,此时使用0代替(void)0;在C中可以自动转换。这个 0 表示进程的虚拟地址空间为 0的地址,这个地址是保留区,这个区域是只读的,没有实际的物理内存映射,因此任何对它的引用都是非法的。但是这种做法在C++中在函数重载的场景下是有问题的,比如函数重载时,NULL 和 0 无法区分。

	void func(int* p)
    {
        cout << "void func(int* p)" << endl;
    }
    void func(int p)
    {
        cout << "void func(int p)" << endl;
    }
    void test2()
    {
        func(nullptr);
        // void func(int* p)
        func(NULL); // 想要调用 func(int* p)
        // void func(int p)
        int* p = NULL;
        func(p);
        // void func(int* p)
        // 因为C++中NULL 就是0。
    }

为了解决这个问题,C++11引入了nullptr,专门用于初始化空类型指针,不同类型指针都可使用nullptr初始化。

    void test3()
    {
        int* p1 = nullptr;
        double* p2 = nullptr;
        void* p3 = nullptr;
    }

nullptr实现原理探究:概念性的实现(实际由编译器处理),使用C++类实现如下:
重载了类型转换运算符,使用一个模板 + T (),这个实现operator前边没有返回值,但是在operator前边不允许指定返回值类型,比如:T operator T*() const { return 0; },这是错误的。

    class nullptr_t_impl
    {
    public:
        // 类型转换操作符重载
        template<typename T>
        operator T* () const
        {
            return 0;
        }

        // 可以转换为任何成员指针类型  
        template<typename T, typename U>
        operator T U::* () const
        {
            return 0;
        }

        // 不允许转换为其他类型
        template<typename T>
        operator T() const = delete;

    private:
        // 阻止取地址
        void operator&() const = delete;
    };

    // 全局常量
    const nullptr_t_impl nullptr1 = {};

    // 主要测试函数
    void test()
    {
        cout << "=== nullptr_t_impl 测试用例 ===" << endl;

        // 测试1: 基本指针类型转换
        cout << "\n1. 测试指针类型转换:" << endl;
        int* p_int = nullptr1;  // 编译器内部:nullptr1.operator int*()
        double* p_double = nullptr1;
        char* p_char = nullptr1;
        void* p_void = nullptr1;

        cout << "int* p_int = nullptr1; -> " << p_int << endl;
        cout << "double* p_double = nullptr1; -> " << p_double << endl;
        cout << "char* p_char = nullptr1; -> " << p_char << endl;
        cout << "void* p_void = nullptr1; -> " << p_void << endl;
    }

类似的,凡是类型转换运算符,都不需要有返回值,比如int类型转换运算符,double,bool等类型转换,都是直接operator + 类型(),不需要指定返回值,但是实现时,需要返回指定的类型,实现如下:

  class ConversionExample
    {
    public:
        int value;

        ConversionExample(int v) : value(v) {}

        // 转换为 int
        operator int() const 
        {
            cout << "调用 operator int()" << endl;
            return value;
        }

        // 转换为 double
        operator double() const {
            cout << "调用 operator double()" << endl;
            return static_cast<double>(value);
        }

        // 转换为 bool
        operator bool() const {
            cout << "调用 operator bool()" << endl;
            return value != 0;
        }

        // 转换为字符串指针
        operator const char* () const {
            cout << "调用 operator const char*()" << endl;
            return value > 0 ? "positive" : "zero or negative";
        }
    };

    void test()
    {
        cout << "\n=== 转换操作符类型演示 ===" << endl;

        ConversionExample obj(42);

        // 各种隐式转换
        int i = obj;           // 调用 operator int()
        double d = obj;        // 调用 operator double()
        bool b = obj;          // 调用 operator bool()
        const char* s = obj;   // 调用 operator const char*()

        cout << "int i = " << i << endl;
        cout << "double d = " << d << endl;
        cout << "bool b = " << b << endl;
        cout << "const char* s = " << s << endl;
    }

2.6 lambda表达式

lambda表达式是C++11引入的一个利器,这部分内容在下面这篇文章中进行了详细说明,链接如下:
C++_chapter15_C++重要知识点_lambda,initializer_list

更多推荐