这是ISO C ++标准14.6.4.1实例化的声明
对于函数模板特化,是一个成员函数模板 专业化,或成员函数或静态的专业化 如果专门化是隐式的,则为类模板的数据成员 实例化,因为它是从另一个模板中引用的 专业化和引用它的上下文取决于a 模板参数,专业化的实例化点 封闭专业化的实例化点。除此以外, 紧接着是这种专业化的实例化点 命名空间范围声明或引用的定义 专业化。
如果调用了类模板的函数模板或成员函数 一种使用该函数的默认参数定义的方法 模板或成员函数,默认实例化的点 argument是函数模板或成员的实例化点 功能专业化。
- 醇>
对于类模板特化,类成员模板特化, 或者是类模板的类成员的特化,如果是 specialized是隐式实例化的,因为它是从中引用的 在另一个模板专门化,如果从哪个上下文 引用的特化取决于模板参数,如果是 在实例化之前,不会实例化特化 封闭模板,实例化的重点就在之前 封闭模板的实例化点。否则,要点 这种专业化的实例化紧接着 命名空间范围声明或引用特化的定义。
我无法为整个部分编写程序。我试图从昨天开始为这一部分编写程序。
任何人都可以为我提供一些代码供您理解。
请,通常..我试着问一个或多个积分。在任何部分。但是这里我无法理解本节中的一点。
所以,任何人都可以为我提供一些代码(程序)供这些部分理解。
答案 0 :(得分:5)
我发现这很令人头疼,委员会已more such fun。所以我认为我可能在下面有一些错误。所以请仔细阅读:)
第三段
对于类模板特化,类成员模板特化或类模板的类成员的特化,如果特化是隐式实例化的,因为它是从另一个模板特化中引用的,如果特化的上下文引用依赖于模板参数,并且如果在封闭模板的实例化之前未实例化特化,则实例化的点紧接在封闭模板的实例化之前。
换句话说,如果实例化类模板或类模板的嵌套类,并且导致该实例化的上下文依赖于模板参数,则模板/嵌套类在实例化之前立即实例化。引用它的模板。
其他专业化中的上下文可以依赖于模板参数,主模板的情况,部分特化和类模板的成员,或者不依赖于模板参数,是显式专业化内部引用的情况。
否则[即上下文是非独立的,重点是 这种特化的实例化紧接在命名空间范围声明或引用特化的定义之前。
这种区别很重要。考虑如果从依赖上下文的特化实例化将立即在命名空间范围声明或引用它的定义之前会发生什么
template<typename T, int N>
struct A {
typedef typename A<T, N-1>::type *type;
};
template<typename T>
struct A<T, 0> {
typedef T type;
};
typedef A<int, 2>::type ptr;
此模板应添加N
指针声明符。因此,A<int, 2>
例如int**
。
typedef A<int, 2>::type
周围的上下文是非依赖的,因此在typedef声明之前实例化A<int, 2>
。 在 A<int, 2>
中,我们有A<int, N-1>::type
,它出现在从属上下文中,并引用A<int, 1>::type
。因此,标准要求我们在实例化A<int, 1>
的同一点实例化A<int, 2>
。
如果我们 在引用它的命名空间范围声明之前(在主模板定义之前)实例化它,我们在处理{{1}时不会注意到部分特化A<T, 0>
在`A<int, N-1>::type
中,因为我们会在专门化之前实例化A<int, 1>
。
第二段
这只是在默认参数中查找的名称与在它们用于的函数的其余部分中查找的名称一致(即,它们的POI与其函数模板的POI /类的成员函数相同模板)。
第一段
这与第三段基本相同。但是,函数模板在引用它们的实体之后被实例化,以便可以进行递归使用,如下例所示。相反,类模板在引用它们的实体之前实例化,因为实体要求类类型完整。如果类类型的POI将在该实体之后,则类类型仍然不存在。
A<int, 1>
如果template<typename T>
void f(T);
template<typename T>
struct A {
void g() {
f(0);
}
void h() { /* do a dance */ }
};
template<typename T>
void f(T t) {
A<T> a;
a.h();
}
void g() {
A<int> a;
a.g();
}
在 f
之前被实例化,那么它就无法访问A<int>
,因为此时它还不存在。因此,函数模板在引用它们的实体之后被实例化,并且类模板在引用它们的实体之前被实例化。
答案 1 :(得分:0)
请求一个人纠正我的理解......
我认为下面的代码说明了1和2的含义(根据我的理解):
template<class T> void f1(T t){cout << 0;}
template<class T> void f2(T t, void (*p)(int) = f1){
(*p)(0);
}
void f(double d){cout << 1;}
template<class T> void g(T t){
f1(t); // this is the interesting call.
}
void f1(int t){cout << 2;}
int main(){
g(2);
f2(2);
} // POI for f1(t), Also POI for f2(2)
考虑调用g(2)。在POI,基本上有三个可见的重载(可行):
然而,该调用将路由到'f(int)',因为这是最佳匹配。
以同样的方式,'f2(2)'的POI是main的右括号。从该POI再次查询默认参数'f1'并解析为'f1(int)',这是所有三个可用重载的最佳匹配。 击>
谢谢@litb。在@litb修改我的理解后修改:
double f1(double d){cout << 1; return 0.0;}
template<class T> void f2(T t1, T t2 = f1(T())){}
template<class T> void g(T t){
f1(t); // this is the interesting call.
}
struct A{
friend A f1(A const &){cout << 2; return A();}
};
int main(){
g(A()); // 'f1(t)' resolves to friend function declaration
f2(A()); // The call to 'f1' in default argument also resolves to friend
// function declaration
// This is because for non dependent names, only ADL is performed
// at POI which is at closing brace of main.
} // POI for f1(t), Also POI for f2(2) in that order
请记住,在上述两个调用中,有两个重载是候选。 namspace函数'f1(double)'和友元函数'f1'声明(由于ADL而找到)。由于这是唯一可行的函数,因此调用将解析为友元声明'f1'。
我认为第3点意味着:
template<class A> struct T{
T(int x = 0){}
};
template<class A> struct U{
U():t(f(A())){}
T<A> t;
}; // POI of 'gt' instantiation
T<int> gt(f(2)); // At this point 'f' is not found, hence error
int f(int x){return x;}
int main(){
U<int> u;
} // There are 2 POIs here 'U<int>::T<int>' and 'U<int>' and in that order
// Therefore 'f' is visible from here.