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
    */
  • 相关阅读:
    Assimp对FBX文件中geometric transformations的处理
    VSM
    WSL安装
    [p1880][NOI1995]石子合并
    【日常】集训总结
    【模板】背包
    【济南集训】20191006解题报告
    [P1516]青蛙的约会
    【模板】ST表
    【济南集训】20191001解题报告
  • 原文地址:https://www.cnblogs.com/5iedu/p/12749244.html
Copyright © 2011-2022 走看看