• cpp 模板型别推导


    概述

    template <typename T>
    void f(ParamType parameter);    //ParamType是一个T相关的类型
    f(expr);    //推导T和ParamType的型别
    
    • 1
    • 2
    • 3

    (下文我把const | & |&&称为修饰,注意* 不是修饰 T *可以被视为一个基本类型)
    这里面其实有两步转换
    为了清楚一点写,我在前面定义运算符㊀它的用作在集合{const, &, &&}上的运算.

    • 大部分时候它类似差集,比如 const int&㊀int&=const int , int&& -int&&=int
    • 在面对&&㊀&的时候这么处理 int&& ㊀ int &=int &

    还有运算符㊉也作用在集合{const, &, &&}上

    • 大部分时候它类似并集,比如 const int&㊉int&=const int& , int&& ㊉int&&=int&&
    • 在面对&&㊉&的时候这么处理 int&& ㊉ int &=int &

    规律总结

    通过下面的表格我们可以对这两步变换做总结:

    • 首先是从parameter的类型到T的类型,可以直观得到: parameter类型减去参数修饰类型就是T的类型 比如parameter类型是 int* 参数修饰是* 那么T的类型就是int* -* =int
    • 对于指针,不妨把int* 或者int const*当做单独的class V.V对于规则的适用就和表格里面的int差不多
    • 然后是通过变量的类型得到parameter的类型
      1. 通过parameter去推断 T的类型,这个是比较清晰的 T的类型 = parameter的类型 ㊀ 参数修饰 . 比如 int = const int& ㊀ const & ,int&& ㊀ int &=int &
      2. expr转换为paramter 是比较复杂的,但是里面有一个核心的优先思想: ** 不缩小也不扩大parameter的修饰范围,以求在任何 f 函数下编写的语句不会出错 **
        具体表现在:
        1. 在parameter无修饰或只有const修饰的时候,expr去掉自己所有的修饰转化为paremeter.
        2. 其他情况:变量类型㊉参数修饰=parameter类型

    表格

    注意事项:

    1. const修饰符在基本类型的最近的两边是等同的int const* const==const int* const
    2. const int const* 在cpp的类型推导里面完全等于int const*
    3. lambda 表达式和正常函数的类型返回有一定差异.这里gcc和clang的实现还不一样

    参数符无修饰

    参数定义变量类型参数修饰parameter类型T类型
    int value = 1;intintint
    const int constValue = 2;int constintint
    int& leftCiteValue = value;int&intint
    int&& rightCiteValue = 27;int&&intint
    const int& constLeftCiteValue=value;int const&intint
    const int&& constRightCiteValue=30;int const&&intint
    数值30intintint
    函数返回的30intintint
    lamda 返回的30main::{lambda()#1}main::{lambda()#2}main::{lambda()#2}
    int* ptr = &value;int*int*int*
    int* const valueConstPtr = &value;int* constint*int*
    const int* const constValueConstPtr = &constValue;int const* constint const*int const*

    参数符const修饰

    参数定义变量类型参数修饰parameter类型T类型
    int value = 1;intconstint constint
    const int constValue = 2;int constconstint constint
    int& leftCiteValue = value;int&constint constint
    int&& rightCiteValue = 27;int&&constint constint
    const int& constLeftCiteValue=value;int const&constint constint
    const int&& constRightCiteValue=30;int const&&constint constint
    数值30intconstint constint
    函数返回的30intconstint constint
    lamda 返回的30main::{lambda()#1}constmain::{lambda()#3} constmain::{lambda()#3}
    int* ptr = &value;int*constint* constint*
    int* const valueConstPtr = &value;int* constconstint* constint*
    const int* const constValueConstPtr = &constValue;int const* constconstint const* constint const*

    参数符 & 修饰

    参数定义变量类型参数修饰parameter类型T类型
    int value = 1;int&int&int
    const int constValue = 2;int const&int const&int const
    int& leftCiteValue = value;int&&int&int
    int&& rightCiteValue = 27;int&&&int&int
    const int& constLeftCiteValue=value;int const&&int const&int const
    const int&& constRightCiteValue=30;int const&&&int const&int const
    int* ptr = &value;int*&int*&int*
    int* const valueConstPtr = &value;int* const&int* const&int* const
    const int* const constValueConstPtr = &constValue;int const* const&int const* const&int const* const

    参数符 && 修饰

    参数定义变量类型参数修饰parameter类型T类型
    int value = 1;int&&int&int&
    const int constValue = 2;int const&&int const&int const&
    int& leftCiteValue = value;int&&&int&int&
    int&& rightCiteValue = 27;int&&&&int&int&
    const int& constLeftCiteValue=value;int const&&&int const&int const&
    const int&& constRightCiteValue=30;int const&&&&int const&int const&
    数值30int&&int&&int
    函数返回的30int&&int&&int
    lamda 返回的30main::{lambda()#1}&&main::{lambda()#4}&&main::{lambda()#4}
    int* ptr = &value;int*&&int*&int*&
    int* const valueConstPtr = &value;int* const&&int* const&int* const&
    const int* const constValueConstPtr = &constValue;int const* const&&int const* const&int const* const&

    参数符const &修饰

    参数定义变量类型参数修饰parameter类型T类型
    int value = 1;intconst &int const&int
    const int constValue = 2;int constconst &int const&int
    int& leftCiteValue = value;int&const &int const&int
    int&& rightCiteValue = 27;int&&const &int const&int
    const int& constLeftCiteValue=value;int const&const &int const&int
    const int&& constRightCiteValue=30;int const&&const &int const&int
    数值30intconst &int const&int
    函数返回的30intconst &int const&int
    lamda 返回的30main::{lambda()#1}const &main::{lambda()#5} const&main::{lambda()#5}
    int* ptr = &value;int*const &int* const&int*
    int* const valueConstPtr = &value;int* constconst &int* const&int*
    const int* const constValueConstPtr = &constValue;int const* constconst &int const* const&int const*

    参数符const &&修饰

    参数定义变量类型参数修饰parameter类型T类型
    数值30intconst &&int const&&int
    函数返回的30intconst &&int const&&int
    lamda 返回的30main::{lambda()#1}const &&main::{lambda()#6} const&&main::{lambda()#6}

    参数符*修饰

    参数定义变量类型参数修饰parameter类型T类型
    int* ptr = &value;int**int*int
    int* const valueConstPtr = &value;int* const*int*int
    const int* const constValueConstPtr = &constValue;int const* const*int const*int const

    参数符const *修饰

    参数定义变量类型参数修饰parameter类型T类型
    int* ptr = &value;int*const *int*int
    int* const valueConstPtr = &value;int* constconst *int*int
    const int* const constValueConstPtr = &constValue;int const* constconst *int const*int const

    实验代码

    请使用较新的gcc,clang需要在lambda处做一点修改.

    #include <boost/type_index.hpp>
    
    #include <compare>
    #include <cstddef>
    #include <cstdio>
    #include <iostream>
    #include <istream>
    #include <math.h>
    #include <ostream>
    #include <streambuf>
    #include <string>
    #include <utility>
    #include <valarray>
    #include <vector>
    
    std::vector< std::string > variables;
    std::vector< std::string > exprs;
    std::vector< std::string > noModifiedParamter;
    std::vector< std::string > noModifiedT;
    std::vector< std::string > constModifiedParamter;
    std::vector< std::string > constModifiedT;
    std::vector< std::string > leftCiteModifiedParamter;
    std::vector< std::string > leftCiteModifiedT;
    std::vector< std::string > rightCiteModifiedParamter;
    std::vector< std::string > rightCiteModifiedT;
    std::vector< std::string > constLeftCiteModifiedParamter;
    std::vector< std::string > constLeftCiteModifiedT;
    std::vector< std::string > constRightCiteModifiedParamter;
    std::vector< std::string > constRightCiteModifiedT;
    std::vector< std::string > pointerModifiedParamter;
    std::vector< std::string > pointerModifiedT;
    std::vector< std::string > constPoionterModifiedParamter;
    std::vector< std::string > constPoionterModifiedT;
    template < typename T >
    class NoModified
    {
    public:
        void show( T parameter )
        {
    
            std::cout << "NoModified T type is :" << boost::typeindex::type_id_with_cvr< T >().pretty_name() << std::endl;
            std::cout << "NoModified parameter type is :" << boost::typeindex::type_id_with_cvr< decltype( parameter ) >().pretty_name() << std::endl;
        }
    
    private:
    };
    
    template < typename T >
    void NoModifiedShow( T parameter )
    {
        noModifiedParamter.emplace_back( boost::typeindex::type_id_with_cvr< decltype( parameter ) >().pretty_name() );
        noModifiedT.emplace_back( boost::typeindex::type_id_with_cvr< T >().pretty_name() );
    }
    
    template < typename T >
    void ConstModifiedShow( const T parameter )
    {
        constModifiedParamter.emplace_back( boost::typeindex::type_id_with_cvr< decltype( parameter ) >().pretty_name() );
        constModifiedT.emplace_back( boost::typeindex::type_id_with_cvr< T >().pretty_name() );
    }
    template < typename T >
    void LeftCiteModifiedShow( T& parameter )
    {
        leftCiteModifiedParamter.emplace_back( boost::typeindex::type_id_with_cvr< decltype( parameter ) >().pretty_name() );
        leftCiteModifiedT.emplace_back( boost::typeindex::type_id_with_cvr< T >().pretty_name() );
    }
    template < typename T >
    void RightCiteModifiedShow( T&& parameter )
    {
        rightCiteModifiedParamter.emplace_back( boost::typeindex::type_id_with_cvr< decltype( parameter ) >().pretty_name() );
        rightCiteModifiedT.emplace_back( boost::typeindex::type_id_with_cvr< T >().pretty_name() );
    }
    template < typename T >
    void ConstLeftCiteShow( const T& parameter )
    {
        constLeftCiteModifiedParamter.emplace_back( boost::typeindex::type_id_with_cvr< decltype( parameter ) >().pretty_name() );
        constLeftCiteModifiedT.emplace_back( boost::typeindex::type_id_with_cvr< T >().pretty_name() );
    }
    template < typename T >
    void ConstRightCiteShow( const T&& parameter )
    {
        constRightCiteModifiedParamter.emplace_back( boost::typeindex::type_id_with_cvr< decltype( parameter ) >().pretty_name() );
        constRightCiteModifiedT.emplace_back( boost::typeindex::type_id_with_cvr< T >().pretty_name() );
    }
    template < typename T >
    void PointerModifiedShow( T* parameter )
    {
        pointerModifiedParamter.emplace_back( boost::typeindex::type_id_with_cvr< decltype( parameter ) >().pretty_name() );
        pointerModifiedT.emplace_back( boost::typeindex::type_id_with_cvr< T >().pretty_name() );
    }
    template < typename T >
    void ConstPointerModifiedShow( T* parameter )
    {
        constPoionterModifiedParamter.emplace_back( boost::typeindex::type_id_with_cvr< decltype( parameter ) >().pretty_name() );
        constPoionterModifiedT.emplace_back( boost::typeindex::type_id_with_cvr< T >().pretty_name() );
    }
    
    void showNoModified()
    {
        printf( "## 参数符无修饰\n" );
        printf( "| 参数定义 | 变量类型 | 参数修饰 | parameter类型 | T类型 |\n" );
        printf( "| -- | -- | -- | -- | -- |\n" );
        for ( size_t i = 0; i < variables.size(); i++ ) {
            printf( "| %s | %s | %s | %s | %s |\n", variables[ i ].c_str(), exprs[ i ].c_str(), "  ", noModifiedParamter[ i ].c_str(), noModifiedT[ i ].c_str() );
        }
    }
    void showConstModified()
    {
        printf( "## 参数符const修饰\n" );
        printf( "| 参数定义 | 变量类型 | 参数修饰 | parameter类型 | T类型 |\n" );
        printf( "| -- | -- | -- | -- | -- |\n" );
        for ( size_t i = 0; i < variables.size(); i++ ) {
            printf( "| %s | %s | %s | %s | %s |\n", variables[ i ].c_str(), exprs[ i ].c_str(), " const  ", constModifiedParamter[ i ].c_str(), constModifiedT[ i ].c_str() );
        }
    }
    void showLeftCiteModified()
    {
        printf( "## 参数符 & 修饰\n" );
        printf( "| 参数定义 | 变量类型 | 参数修饰 | parameter类型 | T类型 |\n" );
        printf( "| -- | -- | -- | -- | -- |\n" );
        for ( size_t i = 0; i < variables.size(); i++ ) {
            if ( i < 6 ) {
                printf( "| %s | %s | %s | %s | %s |\n", variables[ i ].c_str(), exprs[ i ].c_str(), " & ", leftCiteModifiedParamter[ i ].c_str(), leftCiteModifiedT[ i ].c_str() );
            }
            if ( i > 8 ) {
                printf( "| %s | %s | %s | %s | %s |\n", variables[ i ].c_str(), exprs[ i ].c_str(), " & ", leftCiteModifiedParamter[ i - 3 ].c_str(), leftCiteModifiedT[ i - 3 ].c_str() );
            }
        }
    }
    void showRightCiteModified()
    {
        printf( "## 参数符 && 修饰\n" );
        printf( "| 参数定义 | 变量类型 | 参数修饰 | parameter类型 | T类型 |\n" );
        printf( "| -- | -- | -- | -- | -- |\n" );
        for ( size_t i = 0; i < variables.size(); i++ ) {
            printf( "| %s | %s | %s | %s | %s |\n", variables[ i ].c_str(), exprs[ i ].c_str(), " && ", rightCiteModifiedParamter[ i ].c_str(), rightCiteModifiedT[ i ].c_str() );
        }
    }
    
    void showConstLeftModified()
    {
        printf( "## 参数符const &修饰\n" );
        printf( "| 参数定义 | 变量类型 | 参数修饰 | parameter类型 | T类型 |\n" );
        printf( "| -- | -- | -- | -- | -- |\n" );
        for ( size_t i = 0; i < variables.size(); i++ ) {
            printf( "| %s | %s | %s | %s | %s |\n", variables[ i ].c_str(), exprs[ i ].c_str(), " const & ", constLeftCiteModifiedParamter[ i ].c_str(), constLeftCiteModifiedT[ i ].c_str() );
        }
    }
    void showConstRightModified()
    {
        printf( "## 参数符const &&修饰\n" );
        printf( "| 参数定义 | 变量类型 | 参数修饰 | parameter类型 | T类型 |\n" );
        printf( "| -- | -- | -- | -- | -- |\n" );
        for ( size_t i = 0; i < variables.size(); i++ ) {
            if ( i == 6 || i == 7 || i == 8 ) {
                printf( "| %s | %s | %s | %s | %s |\n", variables[ i ].c_str(), exprs[ i ].c_str(), " const && ", constRightCiteModifiedParamter[ i - 6 ].c_str(),
                        constRightCiteModifiedT[ i - 6 ].c_str() );
            }
        }
    }
    
    void showPointerModified()
    {
        printf( "## 参数符*修饰\n" );
        printf( "| 参数定义 | 变量类型 | 参数修饰 | parameter类型 | T类型 |\n" );
        printf( "| -- | -- | -- | -- | -- |\n" );
        for ( size_t i = 0; i < variables.size(); i++ ) {
            if ( i == 9 || i == 10 || i == 11 ) {
                printf( "| %s | %s | %s | %s | %s |\n", variables[ i ].c_str(), exprs[ i ].c_str(), " * ", pointerModifiedParamter[ i - 9 ].c_str(), pointerModifiedT[ i - 9 ].c_str() );
            }
        }
    }
    void showConstPoinerModified()
    {
        printf( "## 参数符const *修饰\n" );
        printf( "| 参数定义 | 变量类型 | 参数修饰 | parameter类型 | T类型 |\n" );
        printf( "| -- | -- | -- | -- | -- |\n" );
        for ( size_t i = 0; i < variables.size(); i++ ) {
            if ( i == 9 || i == 10 || i == 11 ) {
                printf( "| %s | %s | %s | %s | %s |\n", variables[ i ].c_str(), exprs[ i ].c_str(), " const * ", constPoionterModifiedParamter[ i - 9 ].c_str(), constPoionterModifiedT[ i - 9 ].c_str() );
            }
        }
    }
    int getNumber( int i )
    {
        return i;
    }
    int main( int argc, const char** argv )
    {
        int value = 1;
        variables.emplace_back( "int value = 1;" );
        exprs.emplace_back( boost::typeindex::type_id_with_cvr< decltype( value ) >().pretty_name() );
        const int constValue = 2;
        variables.emplace_back( "const int constValue = 2;" );
        exprs.emplace_back( boost::typeindex::type_id_with_cvr< decltype( constValue ) >().pretty_name() );
    
        int& leftCiteValue = value;
        variables.emplace_back( "int& leftCiteValue = value;" );
        exprs.emplace_back( boost::typeindex::type_id_with_cvr< decltype( leftCiteValue ) >().pretty_name() );
        int&& rightCiteValue = 27;
        variables.emplace_back( "int&& rightCiteValue = 27;" );
        exprs.emplace_back( boost::typeindex::type_id_with_cvr< decltype( rightCiteValue ) >().pretty_name() );
    
        const int& constLeftCiteValue = value;
        variables.emplace_back( "const int& constLeftCiteValue=value;" );
        exprs.emplace_back( boost::typeindex::type_id_with_cvr< decltype( constLeftCiteValue ) >().pretty_name() );
        const int&& constRightCiteValue = 30;
        variables.emplace_back( "const int&& constRightCiteValue=30;" );
        exprs.emplace_back( boost::typeindex::type_id_with_cvr< decltype( constRightCiteValue ) >().pretty_name() );
        // 30
        variables.emplace_back( "数值30" );
        exprs.emplace_back( boost::typeindex::type_id_with_cvr< decltype( 30 ) >().pretty_name() );
        // function return 30
        variables.emplace_back( "函数返回的30" );
        exprs.emplace_back( boost::typeindex::type_id_with_cvr< decltype( getNumber( 30 ) ) >().pretty_name() );
        // lambda表达式
        variables.emplace_back( "lamda 返回的30" );
        exprs.emplace_back( boost::typeindex::type_id_with_cvr< decltype( []() { return 30; } ) >().pretty_name() );
        int* ptr = &value;
        variables.emplace_back( "int* ptr = &value;" );
        exprs.emplace_back( boost::typeindex::type_id_with_cvr< decltype( ptr ) >().pretty_name() );
        int* const valueConstPtr = &value;
        variables.emplace_back( "int* const valueConstPtr = &value;" );
        exprs.emplace_back( boost::typeindex::type_id_with_cvr< decltype( valueConstPtr ) >().pretty_name() );
        const int* const constValueConstPtr = &constValue;
        variables.emplace_back( "const int* const constValueConstPtr = &constValue;" );
        exprs.emplace_back( boost::typeindex::type_id_with_cvr< decltype( constValueConstPtr ) >().pretty_name() );
    
        // T
        NoModifiedShow( value );
        NoModifiedShow( constValue );
        NoModifiedShow( leftCiteValue );
        NoModifiedShow( rightCiteValue );
        NoModifiedShow( constLeftCiteValue );
        NoModifiedShow( constRightCiteValue );
        NoModifiedShow( 30 );
        NoModifiedShow( getNumber( 30 ) );
        NoModifiedShow( []() { return 30; } );
        NoModifiedShow( ptr );
        NoModifiedShow( valueConstPtr );
        NoModifiedShow( constValueConstPtr );
    
        // const T
        ConstModifiedShow( value );
        ConstModifiedShow( constValue );
        ConstModifiedShow( leftCiteValue );
        ConstModifiedShow( rightCiteValue );
        ConstModifiedShow( constLeftCiteValue );
        ConstModifiedShow( constRightCiteValue );
        ConstModifiedShow( 30 );
        ConstModifiedShow( getNumber( 30 ) );
        ConstModifiedShow( []() { return 30; } );
        ConstModifiedShow( ptr );
        ConstModifiedShow( valueConstPtr );
        ConstModifiedShow( constValueConstPtr );
    
        //&
        LeftCiteModifiedShow( value );
        LeftCiteModifiedShow( constValue );
        LeftCiteModifiedShow( leftCiteValue );
        LeftCiteModifiedShow( rightCiteValue );
        LeftCiteModifiedShow( constLeftCiteValue );
        LeftCiteModifiedShow( constRightCiteValue );
        // LeftCiteModifiedShow( 30 );
        // LeftCiteModifiedShow( getNumber( 30 ) );
        // LeftCiteModifiedShow( []() { return 30; } );
        LeftCiteModifiedShow( ptr );
        LeftCiteModifiedShow( valueConstPtr );
        LeftCiteModifiedShow( constValueConstPtr );
    
        //&&
        RightCiteModifiedShow( value );
        RightCiteModifiedShow( constValue );
        RightCiteModifiedShow( leftCiteValue );
        RightCiteModifiedShow( rightCiteValue );
        RightCiteModifiedShow( constLeftCiteValue );
        RightCiteModifiedShow( constRightCiteValue );
        RightCiteModifiedShow( 30 );
        RightCiteModifiedShow( getNumber( 30 ) );
        RightCiteModifiedShow( []() { return 30; } );
        RightCiteModifiedShow( ptr );
        RightCiteModifiedShow( valueConstPtr );
        RightCiteModifiedShow( constValueConstPtr );
    
        // const T&
        ConstLeftCiteShow( value );
        ConstLeftCiteShow( constValue );
        ConstLeftCiteShow( leftCiteValue );
        ConstLeftCiteShow( rightCiteValue );
        ConstLeftCiteShow( constLeftCiteValue );
        ConstLeftCiteShow( constRightCiteValue );
        ConstLeftCiteShow( 30 );
        ConstLeftCiteShow( getNumber( 30 ) );
        ConstLeftCiteShow( []() { return 30; } );
        ConstLeftCiteShow( ptr );
        ConstLeftCiteShow( valueConstPtr );
        ConstLeftCiteShow( constValueConstPtr );
    
        // const T&&
        // ConstRightCiteShow(value);
        // ConstRightCiteShow(constValue);
        // ConstRightCiteShow(leftCiteValue);
        // ConstRightCiteShow(rightCiteValue);
        // ConstRightCiteShow(constLeftCiteValue);
        // ConstRightCiteShow(constRightCiteValue);
        ConstRightCiteShow( 30 );
        ConstRightCiteShow( getNumber( 30 ) );
        ConstRightCiteShow( []() { return 30; } );
        // ConstRightCiteShow(ptr);
        // ConstRightCiteShow(valueConstPtr);
        // ConstRightCiteShow(constValueConstPtr);
    
        // T*
        // PointerModifiedShow(value);
        // PointerModifiedShow(constValue);
        // PointerModifiedShow(leftCiteValue);
        // PointerModifiedShow(rightCiteValue);
        // PointerModifiedShow( constLeftCiteValue );
        // PointerModifiedShow( constRightCiteValue );
        // PointerModifiedShow(30);
        // PointerModifiedShow(getNumber(30));
        // PointerModifiedShow( []() { return 30; } );
        PointerModifiedShow( ptr );
        PointerModifiedShow( valueConstPtr );
        PointerModifiedShow( constValueConstPtr );
    
        // const T*
        // ConstPointerModifiedShow(value);
        // ConstPointerModifiedShow(constValue);
        // ConstPointerModifiedShow(leftCiteValue);
        // ConstPointerModifiedShow(rightCiteValue);
        // ConstPointerModifiedShow( constLeftCiteValue );
        // ConstPointerModifiedShow( constRightCiteValue );
        // ConstPointerModifiedShow(30);
        // ConstPointerModifiedShow(getNumber(30));
        // ConstPointerModifiedShow( []() { return 30; } );
        ConstPointerModifiedShow( ptr );
        ConstPointerModifiedShow( valueConstPtr );
        ConstPointerModifiedShow( constValueConstPtr );
    
        // print
        showNoModified();
        showConstModified();
        showLeftCiteModified();
        showRightCiteModified();
        showConstLeftModified();
        showConstRightModified();
        showPointerModified();
        showConstPoinerModified();
    
        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
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333
    • 334
    • 335
    • 336
    • 337
    • 338
    • 339
    • 340
    • 341
    • 342
    • 343
    • 344
    • 345
    • 346
    • 347
    • 348
    • 349
    • 350
    • 351
    • 352
    • 353
    • 354
  • 相关阅读:
    Java-IDEA-类注释快捷键
    Allegro Design Entry HDL(OrCAD Capture HDL)原理图是设计快速入门图文教程
    SpringSecurity自定义多Provider时提示No AuthenticationProvider问题的解决方案与原理(一)
    FreeRtos于嵌入式环境的应用
    如何解决 Redis 的并发竞争 key 问题
    Kafka分布式发布订阅消息系统
    5G网络架构与组网部署01--5G网络架构的演进趋势
    【Java】LinkedList模拟实现
    TCP状态转换
    11.WPF绘图
  • 原文地址:https://blog.csdn.net/weixin_43950087/article/details/125397107