<分区>
据我所知,模板实例化只有两个“阶段”:
- 默认(立即),
- 延迟(懒惰)。
默认用于以下成员:
typedef
,- 成员字段。
延迟:
- 函数(静态或非静态)
- 嵌套类型。
这是正确的,还是存在一些关于编译器急于实例化模板的陷阱/规则?
<分区>
据我所知,模板实例化只有两个“阶段”:
默认用于以下成员:
typedef
,延迟:
这是正确的,还是存在一些关于编译器急于实例化模板的陷阱/规则?
最佳答案
完全不正确。模板只有一个阶段 实例化。何时(何地,这是一个重点) 取决于它是如何使用的。我认为你混淆了名字 查找与实例化。
名称查找分两个阶段完成。 (至少如果编译器 符合——VC++ 仍然会出错。)第一个出现 当编译器解析模板定义时;第二 当模板被实例化时。是否看符号 在第一阶段或第二阶段取决于它是否 依赖与否。确定这一点的规则是公平的 复杂,但总的来说:
如果它是一个函数名,它的一个或多个参数 依赖于模板参数,函数名是依赖的, 它将被查找(和函数重载解析) 在实例化时发生,而不是之前。
如果名称由模板参数限定(例如
T::something
,其中 T
是模板参数),它是
依赖。
在类模板的成员中,如果有依赖基
类(在某种程度上依赖于模板的基类
参数),this->
右边的任何内容都是从属的。
(实际规则要复杂得多,但 以上是一个粗略的近似值,可能对大多数人来说已经足够了 用途。)
只是一些区别的例子:
class MyType {};
void func0( double d )
{
std::cout << "called func0( double )" << std::endl;
}
void func1( double, MyType const& )
{
std::cout << "called func1( double )" << std::endl;
}
template <typename T>
int funcT( T const& param )
{
func0( 42 ); // non-dependent
func1( 42, param ); // dependent
}
void func0( int d )
{
std::cout << "called func0( int )" << std::endl;
}
void func1( int, MyType const& )
{
std::cout << "called func1( int )" << std::endl;
}
int
main()
{
funcT( MyType() );
return 0;
}
输出应该是
called func0( double )
called func1( int )
funcT
中对func0
的调用是非依赖的,所以名字查找
只发生在模板被定义的地方,并且
不稍后,当它被实例化时。那时,有
只有一个 func0
,所以它被调用。
funcT
中对 func1
的调用是依赖的(因为它的第二个
参数取决于模板参数),所以会有一个
在实例化时进行额外的名称查找
(在本例中,紧跟在 main
之后)。这个额外的
查找仅使用 ADN,但由于其中一个参数已定义
在全局命名空间中,ADN 将在全局命名空间中查找,并找到
func1
的第二个声明(然后将是
由重载决议选择,因为它是更好的匹配)。
请注意,我无法验证这一点,因为目前,我只 可以访问已损坏的 VC++11。而且它很微妙,所以 我很可能错过了什么。一般规则是 以避免此类歧义。
注意如果func0
没有在模板之前声明
定义,代码不应编译。根据经验,当
从准标准编译器(或 VC++)转移,这是最
错误的常见原因。
另一种常见情况有时会让人感到意外:
template <typename Base>
class Derived : public Base
{
public:
Derived()
{
init(); // Non-dependent lookup, will NOT find any
// function init() in Base!!!
this->init() // Dependent lookup, WILL find
// Base::init, if it exists.
Base::init() // Also dependent.
}
};
通常,如果您正在使用此模式,并在
像 VC++ 这样的准标准编译器,你会得到很多
迁移到更现代的编译器时出现编译器错误。
通过添加 this->
可以很容易地修复它们。然而,如果
还有一个全局函数 init
在模板时可见
已定义,您将调用此函数,不是
基类。如果您为函数选择有意义的名称,
并将全局函数放在命名空间中,你可能不会得到
语义的这种无声变化经常受到打击,但要注意。
关于c++ - C++ 模板的实例化惰性规则,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15632546/