zoukankan      html  css  js  c++  java
  • 第5章 技巧性基础:5.6 变量模板

    5.6 Variable Templates

    5.6 变量模板

    Since C++14, variables also can be parameterized by a specific type. Such a thing is called a variable template.

    从C++14开始,变量也可以通过特定类型进行参数化。这被称为变量模板。

    For example, you can use the following code to define the value of ˇ while still not defining the type of the value:

    例如,你可以使用下面的代码来定义pi的值,但其pi的类型尚未定义。

    template<typename T>
    constexpr T pi{3.1415926535897932385};

    Note that, as for all templates, this declaration may not occur inside functions or block scope.

    注意,对于所有的模板,这段声明都不能出现在函数或块作用域内部。

    To use a variable template, you have to specify its type. For example, the following code uses two different variables of the scope where pi<> is declared:

    要使用变量模板,必须指定其类型。例如,以下代码使用了两个不同的变量,其作用域是声明pi<>模板所在的作用域(译注:即constexpr T pi{3.1415926535897932385};这行语句所属的作用域,而不是实例化pi<double>或pi<float>那行代码所属的作用域!这点很重要!)

    std::cout << pi<double> << '
    ';
    std::cout << pi<float> << '
    ’;

    You can also declare variable templates that are used in different translation units:

    你也可以声明在不同翻译单元中使用的变量模板

    //== header.hpp:
    template<typename T> T val{}; // 零初始化val
    //== 翻译单元 1:
    #include "header.hpp"
    
    int main()
    {
        val<long> = 42;
        print();
    }
    //== 翻译单元 2:
    #include "header.hpp"
    void print()
    {
        std::cout << val<long> << '
    '; // OK: prints 42(译注:此处val<long>为全局变量!)
    }

    Variable templates can also have default template arguments:

    变量模板也可以具有默认模板实参

    template<typename T = long double>
    constexpr T pi = T{3.1415926535897932385};

    You can use the default or any other type:

    可以使用默认或任何其它类型

    std::cout << pi<> << ‘
    ’; //输出long double类型
    std::cout << pi<float> << ‘
    ’; //输出float类型

    However, note that you always have to specify the angle brackets. Just using pi is an error:

    但是,请注意,你总应该指定尖括号。仅使用pi是错误的:

    std::cout << pi << ‘
    ’; //ERROR

    Variable templates can also be parameterized by nontype parameters, which also may be used to parameterize the initializer. For example:

    可以用非类型参数对变量模板进行参数化, 也可以将非类型参数用于初始化器(initializer)的参数化。例如:

    #include <iostream>
    #include <array>
    
    template<int N>
    std::array<int, N> arr{}; // N个元素的数组,零初始化(译注,使用initializer进行初始化)
    
    template<auto N>
    constexpr decltype(N) dval = N; // dval的类型依赖于传入的值
    
    int main()
    {
        std::cout << dval<'c'> << '
    '; // N 为char型的 'c'值。
    
        arr<10>[0] = 42; // 设置全局arr第1个元素的值
        for (std::size_t i = 0; i < arr<10>.size(); ++i) { // 使用arr中的值
            std::cout << arr<10>[i] << '
    ';
        }
    }

    Again, note that even when the initialization of and iteration over arr happens in different translation units the same variable std::array<int,10> arr of global scope is still used.

    请再注意一下,即使arr的初始化和迭代发生在不同的翻译单元中,也仍然使用的是全局作用域中的同一个变量(std::array<int,10> arr)。

    Variable Templates for Data Members

    数据成员的变量模板

    A useful application of variable templates is to define variables that represent members of class templates. For example, if a class template is defined as follows:

    变量模板一个很有用的应用就是定义一些表示类模板成员的变量。例如,如果类模板定义如下:

    template<typename T>
    class MyClass {
    public:
        static constexpr int max = 1000;
    };

    which allows you to define different values for different specializations of MyClass<>, then you can define

    它允许你为MyClass<>的不同特化版本定义不同的值,然后你可以定义

    template<typename T>
    int myMax = MyClass<T>::max;

    so that application programmers can just write

    因此,应用程序员可以就可以编写:

    auto i = myMax<std::string>;

    instead of

    来替换

    auto i = MyClass<std::string>::max;

    This means, for a standard class such as

    这意味着,对于一个标准的类,例如:

    namespace std {
        template<typename T>
        class numeric_limits {
        public:
            ...
            static constexpr bool is_signed = false;
            ...    
        };
    }

    you can define

    可以定义

    template<typename T>
    constexpr bool isSigned = std::numeric_limits<T>::is_signed;

    to be able to write

    就能编写

    isSigned<char>

    instead of

    来替换

    std::numeric_limits<char>::is_signed

    Type Traits Suffix _v

    类型萃取后缀_v

    Since C++17, the standard library uses the technique of variable templates to define shortcuts for all type traits in the standard library that yield a (Boolean) value. For example, to be able to write

    从C++17起,标准库使用变量模板技术,来为库中所有(布尔) 值的类型萃取定义一个快捷方式。例如,为了能用

    std::is_const_v<T> // since C++17

    instead of

    来替换

    std::is_const<T>::value //since C++11

    the standard library defines

    标准库定义了

    namespace std {
        template<typename T>
        constexpr bool is_const_v = is_const<T>::value;
    }

    【编程实验】变量模板及作用域

    #include<iostream>
    using namespace std;
    
    //变量模板
    template<typename T>
    T  var;  //声明变量模板,由于在全局作用域下声明,这也意味着
             //无论是用哪种类型实例化var ,这些对象都属于全局作用域
    
    void test_assign() //为变量模板赋值
    {
        //以下变量的作用域属全局,而不是该函数!
        //因此,可以在其他函数内使用它们
        var<int> = 7;
        var<double> = 3.14;
        var<char> = 'a';
    }
    
    void test_print()
    {
        std::cout << "var<int> = " << var<int> << ", address:" << &var<int> << std::endl;
        std::cout << "var<double> = " << var<double> << ", address:" << &var<double> << std::endl;
        std::cout << "var<char> = " << var<char> << ", address:" << &var<char> << std::endl;
    }
    
    //C++14之前,为了达到定义变量模板的效果,可用类模板或函数模板来替代,但比较复杂
    //替代方案1:使用类模板
    template<typename T>
    struct VAR
    {
        static T var; //此处为声明,需在类外定义
    };
    
    template<typename T>
    T VAR<T>::var;
    
    void test_VAR()
    {
        VAR<int>::var = 10;
        VAR<double>::var = 3.14;
        std::cout << "VAR<int> = " << VAR<int>::var << std::endl;
        std::cout << "VAR<double> = " << VAR<double>::var << std::endl;
    }
    
    //替代方案2:使用函数模板
    template<typename T>
    T PI()
    {
        constexpr T pi = T(3.1415926);
        return pi;
    }
    
    void test_pi()
    {
        std::cout << "PI<int> = " << PI<int>() << std::endl;
        std::cout << "PI<double> = " << PI<double>() << std::endl;
    }
    
    //min的作用域:limist类作用域
    struct limits {
        template<typename T>
        static T min; //静态成员变量,变量模板
    };
    template<typename T>
    T limits::min = {}; //定义min
    
    void test_min()
    {
        limits::min<int> = 3;
        limits::min<double> = 3.14;
        std::cout <<"limits::min<int> = " << limits::min<int> << std::endl;
        std::cout << "limits::min<double> = " << limits::min<double> << std::endl;
    }
    
    
    int main()
    {
        //全局作用域的变量模板
        test_assign();
        test_print();
    
        test_VAR();
        test_pi();
    
        //类作用域的变量模板
        test_min();
    }
    /*输出结果:
    var<int> = 7, address:00B2C138
    var<double> = 3.14, address:00B2C148
    var<char> = a, address:a
    VAR<int> = 10
    VAR<double> = 3.14
    PI<int> = 3
    PI<double> = 3.14159
    limits::min<int> = 3
    limits::min<double> = 3.14
    */
  • 相关阅读:
    Java实现 蓝桥杯VIP 算法提高 阮小二买彩票
    Java实现 蓝桥杯VIP 算法提高 传染病控制
    Java实现 蓝桥杯VIP 算法提高 传染病控制
    Java实现 蓝桥杯VIP 算法提高 传染病控制
    Java实现 蓝桥杯VIP 算法提高 传染病控制
    Java实现 蓝桥杯VIP 算法提高 传染病控制
    Java实现 蓝桥杯VIP 算法提高 企业奖金发放
    Java实现 蓝桥杯VIP 算法提高 企业奖金发放
    让程序后台隐藏运行
    只要你喜欢,并且可以养家糊口,就是好的
  • 原文地址:https://www.cnblogs.com/5iedu/p/12749244.html
Copyright © 2011-2022 走看看