首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

Template parameters and template arguments

每一个模板被一个或多个模板参数参数化,这些参数在模板声明语法的参数列表中表示:

template < parameter-list > declaration

(1)

?

参数列表中的每个参数可以是:

  • 非类型模板参数;
  • 类型模板参数;
  • 模板参数。

非类型模板参数

type name(optional)

(1)

?

type name(optional) = default

(2)

?

type ... name(optional)

(3)

(since C++11)

auto name

(4)

(since C++17)

1%29一个具有可选名称的非类型模板参数.

2%29一个具有可选名称和默认值的非类型模板参数.

3%29 a非类型模板参数包有一个可选的名字。

4%29一个非类型模板参数,其推导类型为%28条,也可能是auto **或包含占位符的任何其他类型。auto%29

类型是以下类型之一:%28可选cv限定,该限定符将被忽略%29:

  • std::nullptr_t自C++11%29以来占28%;
  • 积分型;
  • 值参考类型%28反对或功能%29;
  • 指针类型%28反对或功能%29;
  • 指向成员类型的指针%28指向成员对象或成员函数%29;
  • 枚举类型...

数组和函数类型可以在模板声明中写入,但它们会自动被指向对象的指针替换,而指针将被适当地替换为函数。

当在类模板正文中的表达式中使用非类型模板参数的名称时,它是不可修改的。prvalue除非它的类型是lvalue引用类型。

表单的模板参数。class Foo不是类型的未命名的非类型模板参数。Foo,即使不是这样class Foo是精化类型说明符和class Foo x;宣告x类型Foo...

The type of a non-type template parameter may be deduced if it includes the placeholder keyword auto: template<auto n> struct B { /* ... */ }; B<5> b1; // OK: non-type template parameter type is int B<'a'> b2; // OK: non-type template parameter type is char B<2.5> b3; // error: non-type template parameter type cannot be double

(since C++17)

类型模板参数

typename name(optional)

(1)

?

class name(optional)

(2)

?

typename|class name(optional) = default

(3)

?

typename|class ... name(optional)

(4)

(since C++11)

1%29具有可选名称的类型模板参数。

2%29和1%29完全一样。

3%29具有可选名称和默认值的类型模板参数。

4%29 A型模板参数包有一个可选的名字。

在模板声明的主体中,类型参数的名称是tydurif名称,它将模板实例化时提供的类型化名。

关键字之间没有区别classtypename在类型模板参数声明中。

模板参数

template < parameter-list > typename(C++17)|class name(optional)

(1)

?

template < parameter-list > typename(C++17)|class name(optional) = default

(2)

?

template < parameter-list > typename(C++17)|class ... name(optional)

(3)

(since C++11)

1%29具有可选名称的模板参数。

2%29模板参数,具有可选名称和默认值。

3%29 A模板参数包有一个可选的名字。

Unlike type template parameter declaration, template template parameter declaration can only use the keyword class and not typename.

(until C++17)

在模板声明的正文中,此参数的名称是模板名称%28,需要实例化%29的参数。

二次

代码语言:javascript
复制
template<typename T> class my_array {};
 
// two type template parameters and one template template parameter:
template<typename K, typename V, template<typename> typename C = my_array>
class Map
{
    C<K> key;
    C<V> value;
};

二次

模板参数

要实例化模板,必须用相应的模板参数替换每个模板参数%28类型、非类型或模板%29。为类模板,参数要么显式地提供,从初始化器推导出,%28自C++17%29或默认。为函数模板,这些参数是明确提供的,从语境中推断或者违约。

如果一个参数可以被解释为类型id而表达式,即使相应的模板参数是非类型的,也总是被解释为类型id:

二次

代码语言:javascript
复制
template<class T> void f(); // #1
template<int I> void f(); // #2
void g() {
    f<int()>(); // "int()" is both a type and an expression,
                // calls #1 because it is interpreted as a type
}

二次

模板非类型参数

在实例化具有非类型模板参数的模板时,适用以下限制:

For integral and arithmetic types, the template argument provided during instantiation must be a converted constant expression of the template parameter's type (so certain implicit conversion applies). For pointers to objects, the template arguments have to designate the address of an object with static storage duration and a linkage (either internal or external), or a constant expression that evaluates to the appropriate null pointer or std::nullptr_t value. For pointers to functions, the valid arguments are pointers to functions with linkage (or constant expressions that evaluate to null pointer values). For lvalue reference parameters, the argument provided at instantiation cannot be a temporary, an unnamed lvalue, or a named lvalue with no linkage (in other words, the argument must have linkage). For pointers to members, the argument has to be a pointer to member expressed as &Class::Member or a constant expression that evaluates to null pointer or std::nullptr_t value. In particular, this implies that string literals, addresses of array elements, and addresses of non-static members cannot be used as template arguments to instantiate templates whose corresponding non-type template parameters are pointers to objects.

(until C++17)

The template argument that can be used with a non-type template parameter can be any converted constant expression of the type of the template parameter. template<const int* pci> struct X {}; int ai10; X<ai> xi; // ok: array to pointer conversion and cv-qualification conversion struct Y {}; template<const Y& b> struct Z {}; Y y; Z<y> z; // ok: no conversion template<int (&pa)5> struct W {}; int b5; W<b> w; // ok: no conversion void f(char); void f(int); template<void (*pf)(int)> struct A {}; A<&f> a; // ok: overload resolution selects f(int) The only exceptions are that non-type template parameters of reference and pointer type cannot refer to/be the address of. a subobject (including non-static class member, base subobject, or array element); a temporary object (including one created during reference initialization); a string literal; the result of typeid; or the predefined variable __func__. template<class T, const char* p> class X {}; X<int, "Studebaker"> x1; // error: string literal as template-argument template<int* p> class X {}; int a10; struct S { int m; static int s; } s; X<&a2> x3; // error: address of array element X<&s.m> x4; // error: address of non-static member X<&s.s> x5; // ok: address of static member X<&S::s> x6; // ok: address of static member template<const int& CRI> struct B {}; B<1> b2; // error: temporary would be required for template argument int c = 1; B<c> b1; // ok

(since C++17)

  • 对于整数和算术类型,实例化过程中提供的模板参数必须是转换常数表达式在模板参数%27s中,类型为%28,因此某些隐式转换应用%29。
  • 对于指向对象的指针,模板参数必须使用静态指定对象的地址。存储时间和一个联动%28内或外部%29,或计算为适当的空指针的常量表达式或std::nullptr_t价值。
  • 对于指向函数的指针,有效的参数是指向具有链接%28的函数的指针或计算为空指针值%29的常量表达式的指针。
  • 对于lvalue引用参数,实例化时提供的参数不能是临时的、未命名的lvalue或没有链接%28的命名lvalue--换句话说,参数必须具有链接%29。
  • 对于指向成员的指针,参数必须是指向表示为&Class::Member或计算为空指针的常量表达式或std::nullptr_t价值。

特别是,这意味着字符串文本、数组元素的地址和非静态成员的地址不能用作模板参数来实例化模板,这些模板对应的非类型模板参数是指向对象的指针。

%28在C++17%29之前,可以与非类型模板参数一起使用的模板参数可以是任意的。转换常数表达式模板参数的类型。

模板<Const int%2APCI>struct X{};int ai十;X<ai>XI;//ok:数组到指针转换和cv-资格转换结构Y{};模板<const Y&b>struct Z{};Y y;z<y>Z;//ok:没有转换模板<int%28&pa%29五>结构W{};INT b五;W<b>W;//ok:不转换为空f%28 char%29;void f%28 int%29;模板<void%28%2APF%29%28 int%29>struct A{};A<&f>a;//ok:重载解析选择f%28 int%29

的非类型模板参数是唯一的例外。参照系指针类型不能引用/是其地址。

  • 子对象%28,包括非静态类成员、基子对象或数组元素%29;
  • 临时对象%28,包括在参考初始化29%;
  • 阿字符串文字;
  • 结果类型;
  • 或预定义变量__func__...

模板<类T,Const char%2AP>类X{};X<int,“Studebaker”>x1;//Error:String文字作为模板-参数模板<int%2AP>类X{};int a十结构S{int m;静态int s;};x<&a二>x3;//Error:数组元素X<&s的地址。M>x4;//Error:非静态成员X<&s的地址。S>X5;//ok:静态成员X的地址<&S:s>x6;//ok:静态成员模板的地址<Const int&cri>struct B{};B<1>b2;//Error:模板参数int c=1;B需要临时地址<c>B1;//OK

%28自C++17%29

模板类型参数

类型模板参数的模板参数必须是类型id,这可能是一个不完整类型的名称:

二次

代码语言:javascript
复制
template<typename T> class X {}; // class template
 
struct A; // incomplete type
typedef struct {} B; // type alias to an unnamed type
 
int main()
{
    X<A> x1; // ok: 'A' names a type
    X<A*> x2; // ok: 'A*' names a type
    X<B> x3; // ok: 'B' names a type
}

二次

模板模板参数

模板参数的模板参数必须是ID-表达式类模板或模板别名的名称。

当参数是类模板时,在匹配参数时只考虑主模板。只有在基于此模板模板参数的专门化碰巧被实例化时,才会考虑部分专门化(如果有的话)。

二次

代码语言:javascript
复制
template<typename T> class A { int x; }; // primary template
template<class T> class A<T*> { long x; }; // partial specialization
 
// class template with a template template parameter V
template<template<typename> class V> class C
{
    V<int> y; // uses the primary template
    V<int*> z; // uses the partial specialization
};
 
C<A> c; // c.y.x has type int, c.z.x has type long

二次

匹配模板参数A到模板模板参数。P的每个模板参数A必须匹配相应的模板参数。P%28直到C++14%29P必须至少和A%28自C++14%29。如果P%27s参数列表包括参数包,0或多个模板参数%28或参数包%29从A它匹配%27s模板参数列表。

二次

代码语言:javascript
复制
template<typename T> struct eval; // primary template 
 
template<template<typename, typename...> class TT, typename T1, typename... Rest>
struct eval<TT<T1, Rest...>> {}; // partial specialization of eval
 
template<typename T1> struct A;
template<typename T1, typename T2> struct B;
template<int N> struct C;
template<typename T1, int N> struct D;
template<typename T1, typename T2, int N = 17> struct E;
 
eval<A<int>> eA; // ok: matches partial specialization of eval
eval<B<int, float>> eB; // ok: matches partial specialization of eval
eval<C<17>> eC; // error: C does not match TT in partial specialization because
                // TT's first parameter is a type template parameter,
                // while 17 does not name a type
eval<D<int, 17>> eD; // error: D does not match TT in partial specialization
                     // because TT's second parameter is a type parameter pack,
                     // while 17 does not name a type
eval<E<int, float>> eE; // error: E does not match TT in partial specialization
                        // because E's third (default) parameter is a non-type

二次

二次

代码语言:javascript
复制
template<class T> class A { /* ... */ };
template<class T, class U = T> class B { /* ... */ };
template <class ...Types> class C { /* ... */ };
 
template<template<class> class P> class X { /* ... */ };
X<A> xa; // OK
X<B> xb; // OK in C++14 after CWG 150
         // Error earlier: not an exact match
X<C> xc; // OK in C++14 after CWG 150
         // Error earlier: not an exact match
 
template<template<class ...> class Q> class Y { /* ... */ };
Y<A> ya; // OK
Y<B> yb; // OK
Y<C> yc; // OK
 
template<auto n> class D { /* ... */ }; // note: C++17
template<template<int> class R> class Z { /* ... */ };
Z<D> zd; // OK
 
template <int> struct SI { /* ... */ };
template <template <auto> class> void FA();  // note: C++17
FA<SI>();  // Error

二次

Formally, a template template-parameter P is at least as specialized as a template template argument A if, given the following rewrite to two function templates, the function template corresponding to P is at least as specialized as the function template corresponding to A according to the partial ordering rules for function templates. Given an invented class template X with the template parameter list of A (including default arguments): Each of the two function templates has the same template parameters, respectively, as P or A. Each function template has a single function parameter whose type is a specialization of X with template arguments corresponding to the template parameters from the respective function template where, for each template parameter PP in the template parameter list of the function template, a corresponding template argument AA is formed. If PP declares a parameter pack, then AA is the pack expansion PP...; otherwise, AA is the id-expression PP. If the rewrite produces an invalid type, then P is not at least as specialized as A.

(since C++14)

  • 这两个函数模板中的每一个都具有相同的模板参数,如PA...
  • 每个函数模板都有一个函数参数,其类型为X使用与相应函数模板中的模板参数相对应的模板参数,其中,对于每个模板参数PP在函数模板的模板参数列表中,对应的模板参数AA已经形成了。如果PP声明一个参数包,然后AA是包的扩展PP...否则,AA是id表达式。PP...

如果重写生成无效类型,则P至少不如A...

%28自C++14%29

默认模板参数

参数列表中的默认模板参数在=签个字。可以为任何类型的模板参数%28类型、非类型或模板%29指定默认值,但不能指定参数包。

如果为主类模板、主变量模板或别名模板的模板参数指定了默认值,则由于C++14%29或别名模板,每个后续模板参数必须具有默认参数,但最后一个模板参数包可能是模板参数包。在函数模板中,只有当参数包具有默认值或可以从函数参数中推断时,参数包才可能后面跟着更多的类型参数。

不允许使用默认参数。

  • 类的类外定义中,成员模板%28必须在类主体%29的声明中提供。
  • 在朋友类模板声明

in any function template declaration or definition

(until C++11)

  • 在任何功能模板声明或定义

%28直到C++11%29

On a friend function template declaration, default template arguments are allowed only if the declaration is a definition, and no other declarations of this function appear in this translation unit.

(since C++11)

出现在声明和定义中的默认模板参数与默认函数参数类似地合并:

二次

代码语言:javascript
复制
template<typename T1, typename T2 = int> class A;
template<typename T1 = int, typename T2> class A;
// the above is the same as the following:
template<typename T1 = int, typename T2 = int> class A;

二次

但是,同一参数不能在同一范围内被赋予默认参数两次。

二次

代码语言:javascript
复制
template<typename T = int> class X;
template<typename T = int> class X {}; // error

二次

模板参数的模板参数列表可以有它们自己的默认参数,这些参数仅在模板参数本身在作用域中有效:

二次

代码语言:javascript
复制
// class template, with a type template parameter with a default
template<typename T = float> struct B {};
 
// template template parameter T has a parameter list, which 
// consists of one type template parameter with a default
template<template<typename = float> typename T> struct A
{
    void f();
    void g();
};
 
// out-of-body member function template definitions
template<template<typename TT> class T>
void A<T>::f()
{
    T<> t; // error: TT has no default in scope
}
template<template<typename TT = char> class T>
void A<T>::g()
{
    T<> t; // ok: t is T<char>
}

二次

成员访问对于默认模板参数中使用的名称,将在声明中检查,而不是在使用点:

二次

代码语言:javascript
复制
class B {};
 
template<typename T> class C
{
    protected:
        typedef T TT;
};
 
template<typename U, typename V = typename U::TT> class D: public U {};
 
D<C<B>>* d; // error: C::TT is protected

二次

The default template argument is implicitly instantiated when the value of that default argument is needed, except if the template is used to name a function: template<typename T, typename U = int> struct S { }; S<bool>* p; // The default argument for U is instantiated at this point // the type of p is S<bool, int>*

(since C++14)

实例

非类型模板参数

二次

代码语言:javascript
复制
#include <iostream>
 
// simple non-type template parameter
template<int N>
struct S { int a[N]; };
 
template<const char*>
struct S2 {};
 
// complicated non-type example
template
<
    char c, // integral type
    int (&ra)[5], // lvalue reference to object (of array type)
    int (*pf)(int), // pointer to function
    int (S<10>::*a)[10] // pointer to member object (of type int[10])
> struct Complicated
{
    // calls the function selected at compile time
    // and stores the result in the array selected at compile time
    void foo(char base)
    {
        ra[4] = pf(c - base);
    }
};
 
S2<"fail"> s2; // error: string literal cannot be used
char okay[] = "okay"; // static object with linkage
S2< &okay[0] > s2; // error: array element has no linkage
S2<okay> s2; // works
 
int a[5];
int f(int n) { return n; }
 
int main()
{
    S<10> s; // s.a is an array of 10 int
    s.a[9] = 4;
 
    Complicated<'2', a, f, &S<10>::a> c;
    c.foo('0');
 
    std::cout << s.a[9] << a[4] << '\n';
}

二次

产出:

二次

代码语言:javascript
复制
42

二次

缺陷报告

以下行为更改缺陷报告追溯应用于先前发布的C++标准。

DR

Applied to

Behavior as published

Correct behavior

CWG 150

C++14

template-template arguments had to match parameter lists of template-template parameters exactly

more specialized also allowed

代码语言:txt
复制
 ? cppreference.com

在CreativeCommonsAttribution下授权-ShareAlike未移植许可v3.0。

扫码关注腾讯云开发者

领取腾讯云代金券

http://www.vxiaotou.com