C++ 基础技术再深入(模板)template parameter和template argument(10)---《C++ Templates》

2023-11-09

参数化声明

template和class或者function的区别在于templates声明语句有一个参数化子句:
template <…parameters here…>
或者:
export template <…parameters here>
如下展示两种templates:一种在class之内,即member templates,另一种在class之外且namespace scope之内(global scope也被当成一种namespace scope):

template <typename T>
class List{//namespace scope class template
public:
    template <typename T2>
    List(List<T2> const&);//member function template
    ...
};

template <typename T>
template <typename T2>
List<T>::List(List<T2> const& b){
    ...
}
template <typename T>
int Length(List<T> const&);//namespace scope function template

class Collection{
    template<typename T>
    class Node{//member class template
        ...
    };

    template <typename T>
    class Handle;//member class template,无定义

    template <typename T>
    T* alloc(){//member function template,隐寓为inline函数
        ...
    }
    ...
};

template <typename T>
class Collection::Handle{//member class template
    ...
};

定义域class外的member templates可有多重template <<…>…>参数化子句,其中一个代表template本身,其余各个子句代表外围的每一层class template。这些子句必须从最外层的class templates开始写起。

function template可以有预设的调用自变量,和一般function一样:

template <typename T>
void report_top(Stack<T> const&,int number=10);

template <typename T>
void fill(Array<T>*,T const&=T());//若T为内建类型,T()为0或者false

当fill()被调用时,如果调用者提供了第二自变量值,预设自变量便不会被实例化,这可确保如果预设自变量无法别某个特定类型T实例化的时候,不会引发编译错误。举例如下:

class value{
public:
    Value(int);
};
void init(Array<Value>* array){
    Value zero(0);
    fill(array,zero);//OK
    fill(array);//ERROR:Value没有default构造函数,所以调用失败
}

除了两种template基本类型,另有三种声明也可以被参数化,三者均相当于class template的成员定义:
1)class templates的成员函数定义;
2)class templates的nested class members(嵌套类别成员)定义;
3)class templates的static成员变量定义。
虽然它们也可以被参数化,但是它们并不是第一级templates。它们的参数完全由它们所隶属的template决定。示例如下:

template <int I>
class CupBoard{
    void open();
    class Shelf;
    static double total_weight;
    ...
}

template <int I>
void CupBoard<T>::open(){
    ...
}
template <int I>
class CupBoard<I>::Shelf{
    ...
};
template <int I>
double CupBoard<I>::total_weight=0.0;
  • 虚拟成员函数

member function templates不能被声明为virtual,这个限制的原因在于:虚拟函数调用机制使用一个大小固定的表格,其中每一笔条目记录一个虚拟函数入口,然而直到整个程序编译完成后才能知道有多少个member function templates需要被实例化,因此和虚拟函数调用机制冲突。
但是class template members却可以是virtual函数,因为class被实例化时候,member function的数量早就确定了,因此可以为虚拟函数。

template <typename T>
class Dynamic{
public:
    //class template的member function,可以被声明为virtual
    virtual ~Dynamic();
    //member function template,不可以被声明为virtual
    template <typename T2>
    virtual void copy(T2 const&);
};
  • template的命名机制

每个template在其作用域内必须有一个独一无二的名称,除非是被重载的function templates。需要特别注意的是class template不能喝其他不同种类的物体共享同一个名称,这点与一般的non-template class不同。

int C;
class C;//class名称和nonclass名称处在不同的空间内

int X;
template <typename T>
class X;//ERROR:名称与上述变量X冲突

struct S;
template <typename T>
class S;//ERROR:名称与上述struct S冲突

template通常使用外部链接,但不能使用C链接方式,惟一例外是static namespace scope function templates,函数内部不能再声明template,默认为:

extern "C++" tempalte <typename T>
void normal();

还有一种非标准形式的链接

extern "Xroma" template <typename T>
void Xroma_link();
tempalte <typename T>
void external();//直射另一个文件中同名且作用域相同的物体

tempalte <typename T>
static void internal();//与另一个文件中的同名template无关
  • Primary Template(主模板/原始模板)

主模板的声明语句在template名称之后并不添加由角括号括起来的template argument list

template <typename T> class Box;//OK:primary template
template <typename T> class Box<T>;//error:non-primary template
template <typename T> void translate(T*);//ok:primary template
template <tyepname T> void translate<T>(T*);//error:non-primary template

一旦我们声明一个偏特化的template,就产生了一个non-primary template。

Template Parameter(模板参数)

template parameters有三种类型:
1)Type parameters(类型参数):
2)Nontype parameters(非类型参数):
3)template template parameters(双重模板参数)。
template parameters是在template声明语句的参数化子句中生命的变量,template parameters不一定得具名:

template <typename,int>
class X;

但是当template程序代码中需要用到某个template parameter时,后者必须具名,注意:后面声明的template parameters可以用到前面声明的template parameters的名称:

template <typename T,T* Root,template <T*> class Buf>
class Structure;

下面我们各个击破。

  • Type Parameters(类别参数)

类别参数由关键字typename或者class导入,两者完全等价,声明方式是:关键词typename或class后面跟一个简单的标识符,该符号后面可以跟一个逗号以便区隔下一参数,也可以使用一个右角括号结束子句,或者跟一个等号表示预设模板自变量。
template声明语句中type parameter的作用非常类似typedef的名称。例如,你不能使用class T这样的名称,及时T确实表示一个class。

template <typename Allocator>
class List{
    class Allocator* allocator;//ERROR
    friend class Allocator;//ERROR
    ...
};
  • Nontype Parameters(非类型参数)

非类型参数实质可以在编译期或者链接期就可以确定其值的常数。这种参数的类型必须是如下三者之一:
整数(int)或者enum类型;
pointers:指向常规objects、执行functions和指向members;
reference:指向objects和指向functions。
你可能惊喜的发现,nontype parameter前面也可以有typename,示例如下:

template <typename T,typename T::Allocator* Allocator>
class List;

Nontype parameters也可以是function类型或者array类型,但它们都会退化为对应的pointer类型:

template<int buf[5]>
class Lexer;
tempalte <int* buf>
class Lexer;

Nontype template parameters的声明防护四非常类似于变量声明,但你不能加上诸如static、mutable之类的修饰,但是却可以加上const或者volatile,但如果这些修饰词出现在参数类型的最外层,编译器会忽略它们:

template <int const length> //const被忽略
class Buffer;
template <int length>
class Buffer;//与上一行声明语句等价

最后,强调一下,non type parameters总是右值:不能被取址,也不能被赋值。

Template Template Parameters(双重模板参数)
Template Template Parameter是一种class template占位符号,其声明方式和class templates类似,只是不能够使用关键词struct和union。

template <template<typename X> class C>//OK
void f(C<int>* p);

template <template<typename X> struct C>//ERROR:不能使用关键词struct
void f(C<int>* p);

template <template<typename X> union C>//ERROR:不能使用关键词 union
void f(C<int>* p);

在它们的作用域内,你可以像使用class template那样地使用template template parameters。
Template template paramters的参数也可以有default template arguments(预设模板自变量)。如果客户端没有为相应的参数指定自变量,编译器就会使用这些预设自变量:

template <template <typename T,typename A=MyAllocator> class Container>
class Adaptation{
    Container<int> storage;//等价于Container<int,MyAllocator>
    ...
};

在template template parameters中,template parameter的名称只能被用于template template parameter的其他参数声明中,示例如下:

template <template<typename T,T*> class Buf>
class Lexer{
    static char storage[5];
    Buf<char,&lexer<Buf>::storage[0]> buf;
    ...
};
template <template<typename T> class List>
class Node{
    static T* storage;//ERROR:这里不能使用template template parameters的参数T
    ...
};

为了防止上面的问题出现,通常template template parameter中template parameters名称并不会在其他地方别用到,因此,未被用到的template parameter可以不具名,示例如下:

template <template <typename,typename=MyAllocator> class Container>
class Adaption{
    Container<int> storage;//等价于Container<int,MyAllocator>
    ...
};
  • Default Template Arguments(预设模板引数)

预设模板引数的设定大家可以参考这篇博客:default template arguments for both function and class templates
无论何种template parameters都可以有预设自变量,当然它必须匹配对应参数,很明显,预设模板自变量不能依赖于其自身参数,但可以相依赖于它之前声明的参数:

template <typename T,typename Allocator=allocator<T> >
class list;

和函数的预设自变量一样,某个参数带有预设自变量的条件是:后续所有参数也都有预设自变量。
后续参数的Usher自变量通常卸载同一个template声明语句中,但也可以写在该template更早的某个声明语句中。例如:

template <typename T1,typename T2,typename T3,typename T4=char,typename T5=char>
class Quintuple;//OK

template <typename T1,typename T2,typename T3=char,typename T4,typename T5>
class Quintuple;//OK

template <typename T1=char,typename T2,typename T3,typename T4,typename T5>
class Quintuple;//ERROR:T1不能拥有默认值,因为T2没有默认值

同时我们也不能重复指定默认模板引数

template <typename T=void>
class Value;

template <typename T=void>
class Value;//ERROR:预设自变量被重复定义了

Template Arguments(模板引数)

Template Arguments是编译器实例化一个template时用来替换template parameters的值。编译器以数种不同的机制来决定以何值替换template parameters:在带有参数P1,P2…的class template X作用域中,template X的名称与template-id

template <typename T>
inline T const& max(T const& a,T const& b){
    return a<b?b:a;
}
int main(){
    max<double>(1.0,-3.0);
    max(1.0,-3.0);
    max<int>(1.0,3.0);
}

但是需要注意有的template arguments无法被推导获得,我们最好将这一类参数放在template parameter list的最前面,这样客户端只需明白指定编译器无法推导的那些自变量即可,其余自变量仍可被自动推导获得:

template <typename DstT,typename SrcT>
//由于DstT不出现在自变量列,无法进行自变量推导
inline DstT implicit_cast(SrcT const& x){
    return x;
}
int main(){
    double value=implicit_cast<double>(-1);//OK,这样编译器可以自动推导SrcT参数
    return 0;
}

如果我们将template paramter的顺序换一下呢?

template <typename SrcT,typename DstT>
inline DstT implicit_cast(SrcT const& x){
    double value=implicit<int,double>(-1));
    return 0;
}

这样我们就需要将两个参数的类型明确给定了,因为SrcT在前面,在推导时候编译器可以确定,但是后面的需要给定默认的值,因此两种类型的值都必须明确指定。

由于function template可以被重载,因此及时写出一个function template的所有自变量,可能也不足以使得编译器确定到底该调用哪种函数,实例如下:

template <typename Func,typename T>
void apply(Func func_ptr,T x){
    func_ptr(x);
}

template <typename T>
void single(T);

template <typename T>
void multi(T);
template <typename T>
void multi(T*);

int main(){
    apply(&single<int>,3);//OK
    apply(&multi<int>,7);//ERROR:符合multi<int>形式的函数不只一个
    return 0;
}

不仅如此,明确指定template arguments还可能导致构建出不合法的C++类型,考虑如下的重载函数:

template <typename T> RT1 test(typename T::X const*);
template <typename T> RT2 test(...);

算是test<int>对于第一个function template而言是没有意义的,因为int类型并没与member type X,然而第二个function template没有这种问题,因此算式&test<int>可以明确制定出惟一一个函数地址。于是尽管第一个template以int替换失败,却并没有造成&test<int>随之不合法。正式SFINAE(替换失败并非错误)这一原则,function template的重载实际可行。看看SFINAE原则在如下代码中的应用:

template <int N>
int g(){
    return N;
}
template <int* P>
int g(){
    return *P;
}
int main(){
    return g<1>();//1无法适用于int*参数,SFINAE原则在这里起了重要的作用
    return 0;
}
  • Type template Arguments(型别引数)

template type arguments是针对template type parameters而指定的值,我们管用的大多数types都可以作为template arguments使用,但有两个例外:
1)local classes和local enum types不能作为template type arguments使用;
2)如果某个type涉及无名的class types或者无名的enum types,这样的type同样也无法作为template type arguments使用,但如果运用typedef使其具名便可以被当做template type arguments使用。

template <typename T>
class List{
    ...
};
typedef struct{
    double x,y,z;
}Point;
typedef enum{red,green,blue} *ColorPtr;

int main(){
    struct Association{
        int *p;
        int *q;
    };
    List<Association*> error1;//ERROR:template arugement不能为local type
    List<ColorPtr> error2;//ERROR:template argument不能为unnamed type
    List<Point> ok;//原本无名的type因typedef而有了名称
    return 0;
}
  • Nontype template Arguments(非类型引数)

Nontype template arguments是针对nontype template parameters(非类型模板参数)而指定的值。下面的nontype template arguments都合法:

template <typename T,T nontype_param>
class C;

C<int,33>* c1;

int a;
C<int*,&a) c2;

void f();
void f(int);
c<void(*)int,f>* c3;//调用f时候,&会被隐寓加入

class {
public:
    int n;
    static bool b;
};
C<bool&,X::b>* c4;//static类成员都可以被接受
C<int X::*,&X::n> c5;

template <typename T>
void templ_func();

C<void(),&templ_func<double> >* c6;

template arguments的一个一般性约束条件是:必须能够在编译期或者链接期求职。只在执行期间才能求值的表达式不能作为nontype template arguments使用;
及时如此,nontype template arguments还不包括:

null pointer常数
浮点数(floating-point numbers)
字符串字面常数(string literals)
derived-to-base转换

不能以字符串字面常量作为nontype template arguments的一个技术难题在于:两个内容相同的字符串字面常量可能存在两个不同的地址上,一种稍显笨拙的方法是引入一个字符串array:

template <char const* str>
class Message;
extern char const hello[]="Hello World!";
Message<hello>* hello_msg;

这里我们必须使用关键词extern,因为const array默认采用内部链接。
下面还有一些错误实例,供大家参考学习:

template <typename T,T nontype_param>
class C;

class Base{
public:
    int i;
}base;
class Derived:public Base{
}derived_obj;
C<Base*,&derived_obj>* error1;//ERROR,derived-to-base不被考虑;
C<int&,base.i>* error2;//ERROR,成员变数不被考虑
int a[10];
C<int*,&a[0]>* error3;//ERROR,不能使用array内某个元素的地址
  • Template Template Arguements(双重模板自变量引数)

Template template argument必须是这样的一个class template,其参数完全匹配待替换之template template parameter的参数。Template template argument的default template argument会被编译器忽略,除非对应的template template parameter有预设的自变量。

#include <list>
template <typename T1,typename T2,template <typename > class Container>
class Relation{
public:
    ...
private:
    Container<T1> dom1;
    Container<T2> dom2;
};
int main(){
    Relation<int,double,std::list> rel;//std::list的提供的template template argument有两个,而对应的template template parameter只有一个预设自变量。
    return 0;
}

问题出在std::list template拥有不止一个参数,第二参数(是个allocator,配置器)有默认值,但编译器把std::list匹配至Container时,该默认值被忽略了。
我们可以将其进行改写:

template <typename T1,typename T2,template <typename T,typename=std::allocator<T> > class Container>
class Relation{
public:
    ...
private:
    Container<T1> dom1;
    Container<T2> dom2;
};

template template parameter不能使用union和struct,猜猜看,template template argument呢?没有这个限定啦,所以开心的玩起来啦!

  • 等价

当两组template arguments的元素意义对等时候,我们称这两组变量等价。对于type arguments,typedef的名称并不印象对比过程最终被比较的是typedef所指代的type。对于整型nontype arguments,比较的是自变量值,与自变量表达式无关:

template <typename T,int I>
class Mix;
typedef int Int;
Mix<int,3*3>* p1;
Mix<Int,4+5>* p2;//p2和p1具有相同的类型

一个由function template产生的函数,和一个常规函数,无论如何不会被编译器视为等价,及时它们的类型和名称完全相同。这对class template造成两个重要结果:
1)由member function template产生的函数不会覆盖虚拟函数;
2)由constructor template产生的构造函数不会被当做default copy构造函数。同样的道理适用于由assignment template产生的assignment运算符不会被当做一个copy-assignment运算符。

Friends

Friend声明语句的基本概念简单:指定某些classes或functions,让它们可以对friend声明语句所在的class进行特权存取。但是下面两种事实使得这个概念变得复杂:
1)friend声明语句可能是某种物体的惟一声明(即friend仅仅在class内部声明,别无其他兄弟);
2)friend函数声明可以就是其定义。

friend class声明语句不能成为一个定义式,这就大大降低了问题的发生,涉及templates时,惟一需要考虑的情况是:你可以把某个class template的特定实体声明为friend:

template <typename T>
class Node;

template <typename T>
class Tree{
    friend class node<T>;
    ...
};  

注意:在class template的某一实体成为其他class或者class template的friend之前,class template Node必须已被声明而且可见,但是对于常规class而言并没有什么限制。

template <typename T>
class Tree{
    friend class Factory;//OK,因为这是常规类Factory的首次声明
    friend class Node<T>;//ERROR,因为之前并没有声明Node
};
  • Friend Functions

function template的具现体可以成为别人的一个friend function,前提是该function template名称之后必须紧跟着以角括号括起来的自变量列-如果编译器可推导出所有自变量,自变量列可以为空:

template <typename T1,typename T2>
void combine(T1,T2);

class Mixer{
    friend void combine<>(int&,int&);
    friend void combine<int,int>(int,int);
    friend void combine<char>(char,int);
    friend void combine<char>(char&,int>;//ERROR,char与char&不匹配
    friend void combine<>(long,long){...}//不能再此处定义函数
};

注意,我们无法定义一个template实体,最多只能定义一个特化体,因此一个令某实体获得名称的friend声明语句,不能是个定义式。如上面代码中的最后一个模板函数试图定义函数。

如果friend后面没有跟着角括号,有如下两种可能:
1)如果这不是个资格修饰名称(亦即不含::),就绝不会一弄某个template实体。如果编译器无法在friend声明处匹配一个non-template function,则这个friend声明便被当做这个函数的首次声明。这个声明语句是个定义式,即non-template function声明;
2)如果这是一个资格修饰名称(亦即含有::),就必定引用一个先前已定义的function或者functionn template。编译器会有限匹配常规non-template函数,然后才匹配function templates。这个friend声明语句不能是个定义式。

void multiply(void*);//常规函数

template <typename T>
void multiply(T);//function template

class Comrades{
    friend void multiply(int){}//定义了一个新函数::multiply(int)
    friend void ::multiply(void*);//引用先前定义的常规函数,即multiply(void*),而非multiply<void*>实体
    friend void ::multiply<double*>(double*);//带有角括号,此时编译器必须见到该template
    friend void ::error(){}//ERROR,带修饰符的friend,不能是个定义
};

上面代码中,我们将friend function声明在常规class中,如果把friend声明在class templates中,先前规则同样适用,而且template parameter可以参与到friend function之内:

template <typename T>
class Node{
    Node<T>* allocate();
    ...
};

template <typename T>
class List{
    friend Node<T>* Node<T>::allocate();
    ...
};

然而将friend function定义域class template中可以引发一个有趣的错误因为任何只在template中被声明的object,都是直到template被实例化后才能成为具现实体。

template <typename T>
class Creator{
    friend void appear(){
        ...
    }
};
Creator<void> miracle;
Creator<double> oops;//ERROR,试图再次生成::appear()

这种问题的解决方法是什么呢?确保class template的template parameters出现在定义于该template之中的所有friend function的类型之中,除非我们想要阻止这个class template在一个文件中被多次实例化,解决方法:

template <typename T>
class Creator{
    friend void feed(Creator<T>*){
        ...
    }
};
Creator<void> one;//OK,生成feed(Creator<void>*)
Creator<double> two;//OK,生成feed(Creator<double>*)

另外还请注意,这些函数被定义于class定义式内,因此它们案子成为inline。而且如果你在两个不同的编译单元中产生同一个函数,编译器都不会认为有错误。

  • Friend Template
class Manager{
    template <typename T>
    friend class task;
    template <typename T>
    friend void Schedule<T>::dispatch(Task<T>*);
    template <typename T>
    friend int ticket{
        return ++Manager::counter;
    }
    static int counter;
};

和常规的friend声明语句一样,只有当friend template产生一个无修饰函数名,而且该名称之后不紧跟着角括号,这个friend template才是一个定义式
friend template只能声明primary templates机器primary templates的成员。任何与primary template相关的偏特化体和明确特化体都将被编译器自动视为friends。

PS:
1)template template parameters(双重模板参数)是一种class templates占位符号,声明方式和class template类似。
2)primary templates指的是没有进行偏特化或者特化的模板类或者模板函数。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++ 基础技术再深入(模板)template parameter和template argument(10)---《C++ Templates》 的相关文章

  • 如何从更高级别启动用户级别的 Exe

    我希望一个进程始终在用户级别运行 当它由以管理员级别运行的安装程序 自定义 而不是 msi 启动时 或者当用户登录时 环顾四周 我不确定这是否可能 最简单的方法是有 2 个进程 一种是普通用户 它启动提升 管理进程 然后管理进程可以使用 I
  • 在单个 C# 泛型方法中返回可为 null 和 null?

    C 泛型方法是否可以返回对象类型或 Nullable 类型 例如 如果我有一个安全的索引访问器List我想返回一个值 稍后我可以使用以下任一方法检查该值 null or HasValue 目前我有以下两种方法 static T SafeGe
  • C++:Linux平台上的线程同步场景

    我正在为 Linux 平台实现多线程 C 程序 其中我需要类似于 WaitForMultipleObjects 的功能 在搜索解决方案时 我发现有一些文章描述了如何在 Linux 中实现 WaitForMultipleObjects 功能
  • C 语言中的套接字如何工作?

    我对 C 中的套接字编程有点困惑 You create a socket bind it to an interface and an IP address and get it to listen I found a couple of
  • C++11 中具有 C 链接的复杂类型

    我需要将 C 库的标头包含到我的 C 11 代码中 现在 标头提供了涉及大量的例程和数据结构double complex到处都是 例如 include
  • 如何在 C++ 中对四元结构进行有效排序?

    我有一个包含 x y z 和 w 成员的结构 如何高效排序 在 C 中首先按 x 然后按 y 按 z 最后按 w 如果你想实现字典排序 那么最简单的方法是使用std tie实现小于或大于比较运算符或函子 然后使用std sort http
  • 枚举 EMF 时丢失文本

    我在列举发票 emf http www mediafire com kdjwvvo7odyvwa6并将其复制到另一个但文本丢失了 令人惊讶的是 当我将其输出到窗口时 它绘制得非常完美 int CALLBACK EnhMetaFileProc
  • 使用 strcpy 从整数生成指针,无需进行强制转换

    我不明白我做错了什么 我正在学习 C 很抱歉 如果这显然是错误的 但我正在尝试使用uthash http uthash sourceforge net 制作股票及其价格的哈希图 但是当我将股票添加到哈希映射时 我收到上述错误 我所做的就是从
  • 如何在方法模板中使用模板类型的引用传递参数?

    我目前正在努力编译以下代码 首先是包含带有方法模板的类的头文件 ConfigurationContext h class ConfigurationContext public template
  • DataGridView小数不排序

    好吧 我有一个 DataGridView 它的数据绑定如下 dataGridViewChartOre AutoGenerateColumns false dataGridViewChartOre DataSource xml GetOreC
  • “已经有一个与此命令关联的打开的 DataReader,必须先将其关闭。”

    我正在开发需要连接到另一个数据库以获取一些数据的应用程序 为此 我决定使用 SqlConnection reader 等 我需要执行一些查询 例如首先我需要获取某个用户的卡 ID 之后我需要通过该卡 ID 获取一些数据 这是我的代码 reg
  • Apple IOS 上的 C# 应用程序 [已关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我有基于 C Net 的应用程序 有什么方法可以在 Apple IOS 上运行这些应用程序吗 我没有资
  • 使用 OpenSSL 库在 C++ 中生成 SHA 哈希值

    如何使用以下命令生成 SHA1 或 SHA2 哈希值OpenSSL https openssl org图书馆 我搜索了谷歌 找不到任何函数或示例代码 从命令行来看 很简单 printf compute sha1 openssl sha1 您
  • 扩展一个类

    编辑回答 虽然我最初的问题并没有完全按照康拉德 鲁道夫提供的答案所解决的方式解释我的需求 但他 无意或有意 基本上为我写了我想写的内容 类本身不会被扩展 但通过使类了解新函数来扩展其功能 这些新函数允许它 类 处理更广泛的问题 我非常感谢您
  • OpenMP 和 C++:this 指针

    Is thisOpenMP 中始终共享指针 尽管编译器不会抱怨以下代码default none pragma omp parallel for default none shared n for SInt i 0 i lt n i f i
  • 如何在控制台程序中获取鼠标位置?

    如何在 Windows 控制台程序中用 C 获取鼠标单击位置 点击时返回鼠标位置的变量 我想用简单的文本命令绘制一个菜单 这样当有人点击时 游戏就会注册它并知道位置 我知道如何做我需要做的一切 除了单击时获取鼠标位置 您需要使用 Conso
  • 为什么.net中的数组只实现IEnumerable而不实现IEnumerable

    我正在实现自己的 ArrayList 类 当我意识到这一点时 我感到很惊讶 public System Collections Generic IEnumerator
  • 使用客户端 hello 消息进行 TLS 协议检测

    我需要检测网络流量中的 https 数据包 到目前为止 我将所有 443 标记为 https 但我不想再在这种情况下使用端口信息 检查客户端问候消息是否足够 Check 22 and version info 0300 0301 or 03
  • 如何重写(重新实现)QFileSystemModel 中的成员函数

    我已经为此苦苦挣扎了一段时间 Qt s QFileSystemModel由于图标获取算法非常糟糕 在获取数百个文件时速度非常慢 我想完全禁用图标 它们被提取到QFileSystemModel data方法不是虚拟的 QFileSystemM
  • 如何将 IDispatch* 放入托管代码中

    我一直在考虑尝试使用 C 编写一个实现 OPOS 服务对象的 COM 对象 我已经使用自动化和 MFC 在 C 中完成了它 这并不太困难 所以我坚持尝试将其转换为一种方法 我将排除界面中的其他方法 因为它们很简单 或者我希望如此 id 6

随机推荐

  • 【软件测试学习笔记】黑盒测试方法及案例

    文章目录 一 黑盒测试基本概念 二 黑盒测试的主要目的 三 优缺点 优点 缺点 四 黑盒测试的策略 五 黑盒测试方法 等价类划分 分类 划分方法 原则 等价类划分案例 边界值分析法 原则 边界值分析法案例 因果图法 四种因果关系 五种约束
  • 05

    1 Harbor简介 Harbor是由VMWare公司开源的容器镜像仓库 实际上 Harbor是在Docker Registry上进行相应的企业级扩展 从而获得了更加广泛的应用 组件 功能 harbor adminserver 配置管理中心
  • CentOS7安装MySQL5.7.26

    安装MySQL 在CentOS中默认安装有MariaDB 这个是MySQL的分支 但为了需要 还是要在系统中安装MySQL 而且安装完成之后可以直接覆盖掉MariaDB 下载并安装MySQL官方的 Yum Repository root l
  • django添加数据库字段进行数据迁移

    1 修改view py里面的变量 2 在model py新增字段 3 打开terminal并将环境切到项目所在环境 切换方式为 4 执行命令 python manage py makemigrations backend python ma
  • Redis(主从复制、哨兵模式、集群)概述及部署

    目录 引言 壹 Redis主从复制 一 Redis的高可用 二 Redis持久化 1 Redis 提供两种方式进行持久化 2 RDB 持久化 三 Redis主从复制 1 Redis主从复制的概念 2 Redis主从复制 四 Redis主从复
  • Linux系统删除文件夹下所有文件

    这篇文章来为大家介绍一下如何在 Linux 系统下删除文件 当 Linux 系统使用时间过长以后 难免会产生一些垃圾文件 这些文件除了会占用磁盘空间之外还会降低系统的运行效率 所以长时间运行后我们需要及时的清理一下这些垃圾文件 rm 是一个
  • 基于Hadoop的云盘系统上传和下载效率优化及处理大量小文件的解决方法

    基于任何平台实现的云盘系统 面临的首要的技术问题就是客户端上传和下载效率优化问题 基于Hadoop实现的云盘系统 受到Hadoop文件读写机制的影响 采用Hadoop提供的API进行HDFS文件系统访问 文件读取时默认是顺序 逐block读
  • 第7章 指针 第6题

    题目 Julian历法是用年及这一年中的第几天来表示日期 设计一个函数将Julian历法表示的日期转换成月和日 如Mar8 注意闰年的问题 函数返回一个字符串 即转换后的月和日 如果参数有错 如天数为第370天 返回NULL 代码 incl
  • superset官方文档的安装和配置

    原文 https superset incubator apache org installation html 下载 git clone https github com apache incubator superset cd incu
  • 数据结构-----顺序表与单链表的实现

    1 顺序表 实现顺序表的初始化 插入 删除 查找 逆置 合并等操作 include
  • Python numpy函数:reshape()

    reshape 是数组对象中的方法 用于改变数组的形状 形状变化是基于数组元素不能改变的 变成的新形状中所包含的元素个数必须符合原来元素个数 如果数组元素发生变化的时候 就会报错 reshape函数生成的新数组和原始数组公用一个内存 也就是
  • 【数据库】数据库入门(七): 函数依赖(Functional Dependencies)

    前言 一个设计良好的数据库模式 database schema 应该要具备以下特点 完整性 Completeness 减少冗余 Redundancy freeness 一致的含义 Consistent understanding 良好的性能
  • QFileInfo获取文件信息

    它可以获取很多文件的信息 比如文件的大小 文件的类型 文件的创建日期等等 下面是获取一些文件信息的方法 先要头文件 include
  • 跨境市场下一个蓝海:区块链+跨境支付?

    全球经济的现在需要跨境支付的场景越来越多 比如出国旅游 求学 海外购物等 但是跨境支付中会面临高昂手续费 交易过程繁琐 收款时间漫长等问题 跨境市场 下一个蓝海 随着近年来跨境电商的迅猛发展 越来越多的优质海外商品郑加速进入中国市场 跨境市
  • vite --- 为什么选Vite

    目录 什么是Vite 为什么选Vite 现实问题 为什么生产环境仍需打包 Vite 与竞品 什么是Vite Vite 法语意为 快速的 发音 vit 发音同 veet 是一种新型前端构建工具 能够显著提升前端开发体验 它主要由两部分组成 一
  • 版本号的正则表达式

    验证版本号的正则表达式 要求 必须是三位 x x x的形式 每位x的范围分别为1 99 0 99 0 99 不允许的情况0 x x 01 x x x 0x x x 00 x x x 00 x x 0x 满足这些条件的正则为 1 9 d 1
  • 电路基础_模拟电路_问答_2023_02

    101 图解分析法 饱和失真和截止失真都是由晶体管输入 输出特性的非线性造成 统称为非线性失真 为减小非线性失真 必须合理选择静态工作点的位置并适当限制输入信号的幅度 图解法分析放大器 1 确定静态工作点 分析电路参数对Q点的影响 2 根据
  • Android http网络请求设置以及设置网络权限

    在project下 一 HTTP网络请求设置 第一步 在res的xml目录下 新建一个xml文件 名称 network security config xml 在 network security config xml 中添加代码
  • 准备离职搞ue4

    确实不合适搞webgl 我决定离职了 得到一个offer UE4 估计看我c 图形学还行吧 年龄偏大 没有UE4经验 也没有长期游戏经验 所以ue4岗位被拒很多 工作机会来之不易 得拼命干了 憋着一肚子气 webgl再努力 也是难以发挥 哎
  • C++ 基础技术再深入(模板)template parameter和template argument(10)---《C++ Templates》

    参数化声明 template和class或者function的区别在于templates声明语句有一个参数化子句 template lt parameters here gt 或者 export template lt parameters