• 《C++标准库第2版》3.2 虽旧犹新的语言特性 笔记


    3.2 虽旧犹新的语言特性

    非类型模板参数

    1.除了类型参数之外,我们也可以为template使用nontype paramatter.

    2.非类型参数看作是template类型的一部分

    bitset<32> flags32;
    bitset<50> flags50;
    // 这两个看作是两个不同类型的template
    
    • 1
    • 2
    • 3

    模板参数默认值

    class template 可以拥有默认参数

    function template也可以拥有默认参数

    // 类模板
    template <typename T1, typename T2 = int>
    class TmpClass1 {};
    
    // no default argument for 'T2',感觉有点像函数的默认参数,一个参数有了默认值,那么这个参数后面的参数都必须有默认值
    // 通过查阅资料:类模板的默认模板参数从右往左开始指定
    // template 
    // class TmpClass2 {};
    
    // 函数模板
    // 这两个都能编译通过
    template <typename T1 = double, typename T2>
    void func(T1 arg1, T2 arg2) {}
    
    template <typename T1, typename T2 = double>
    void func1(T1 arg1, T2 arg2) {}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    关键字typename

    关键值typename用来指明后面紧跟的是个类型

    注意事项:C++的一般性规则是,template内的任何标识符都被视为一个value,除非它加上typename

    #include 
    
    class Q
    {
    public:
        using SubType = int;
    };
    
    template <typename T>
    class MyClass
    {
        // 这样写编译器会直接提示需要在前面加上typename
        // T::SubType *ptr;
        typename T::SubType *ptr;
    
    public:
        MyClass() {}
        ~MyClass() {}
    };
    
    int main(int argc, char const *argv[])
    {
        /* code */
        MyClass<Q> myclassq;
        return 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

    成员模板

    class的成员函数可以是一个template。然而member template不可以是virtual

    通常用来支持class template内的成员之间的自动类型转化。

    #include 
    // 基本用法
    class MyClass
    {
        public:
            MyClass() {}
            ~MyClass() = default;
        template<typename T>
        void f(T a)
        {
            // 这里面的操作是T这个类型支持的。
            ;//
        }
    };
    
    // 常用用法
    template<typename T>
    class MyClass1 
    {
        private:
            T value;
        public:
            template <typename X>
            void assign(const MyClass1<X>&x)
            {
                value = x.getValue();
            }
    
            T getValue() const 
            {
                return value;
            }
    };
    
    void f()
    {
        MyClass1<double> d;
        MyClass1<int> i;
        d.assign(d);
        d.assign(i); 
    }
    
    // 特殊情况: member template 构造函数
    template <typename T>
    class MyClass2
    {
    public:
        // 没有这个会报错:error: no matching function for call to 'MyClass2::MyClass2()'
        MyClass2() {}
        template <typename U>
        MyClass2(const MyClass2<U> &x)
        {
                std::cout << "MyClass(const MyClass&x)" << std::endl;
        }
    };
    
    void f1()
    {
        MyClass2<double> xd;
        MyClass2<double> xd2(xd);
        MyClass2<int> xi(xd);
    
        // 输出结果:只有一次MyClass(const MyClass&x)
        // 通过查阅资料:发现当xd2与xd类型相同时,通过隐式生成的copy构造函数完成。类型不同的时候才通过我们写的那个template
    }
    
    int main(int argc, char const *argv[])
    {
        f();
        f1();
        return 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
    • 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
    • 70
    • 71
    • 72

    嵌套式的class template

    template <typename T>
    class MyClass
    {
    	template<typename T2>
    	class NestedClass {};
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3.2.1 基础类型的明确初始化

    知识点:

    “一个明确的构造函数调用,但不给实参”这样的语法,基础类型会被设定初值0

    如果一个template强迫设置初值为0,其值就是所谓的zero initialized,否则就是default initialized

    int i1;         // undefined value 
    int i2 = int(); // 0
    int i3{};       // 0
    
    • 1
    • 2
    • 3

    利用这一个特性

    template <typename T>
    void f()
    {
        T x = T();
        std::cout << x << std::endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3.2.2 main()定义式

    // 这个是我这补全工具自动补全生成的,没有报错。
    int main(int argc, char const *argv[])
    {
    }
    
    // main的合法定义式
    int main()
    {
    
    }
    
    int main(int argc, char **argv)
    {
    
    }
    
    int main(int argc, char *argv[])
    {
    
    }
    // 通常情况下,会写一个return 0,但是不是必须。
    // 可以使用exit()/quick_exit()/terminate()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
  • 相关阅读:
    腾讯云精彩亮相 2023 长沙·中国 1024 程序员节,共创数智未来!
    三万字带你了解那些年面过的Java八股文
    c++ 空类的大小
    树状数组应用(AcWing 242,243,244)
    <MySQL> 如何合理的设计数据库中的表?数据表设计的三种关系
    深入了解 JavaScript 中的 DOM 和 BOM
    从零开始学习c++全套通关系列(第一章)万字总结,建议收藏~
    【AI视野·今日NLP 自然语言处理论文速览 第五十七期】Wed, 18 Oct 2023
    SaulLM-7B: A pioneering Large Language Model for Law
    ELK技术-Logstash
  • 原文地址:https://blog.csdn.net/m0_37406848/article/details/132903680