模板函数重载的实例化
Instantiation of template function overloads
我知道编译器不会实例化未使用的模板函数,只要它们在类中不是虚拟的。
在一个简单的例子中,如果我有两个重载的模板函数,它们都采用相同的模板参数,那么编译器似乎会实例化这两个重载。我想这是必需的,以便编译器可以执行重载解决?重载是否不受函数模板的延迟实例化规则的约束?我无法在标准中找到相关文本。下面是一个示例:
template<typename T>
void foo(T) {zzz}
template<typename T>
void foo(T*) {}
int main()
{
int* blah;
foo(blah);
}
如果没有实例化第一个重载,我希望没有编译器错误,但是我得到了错误。
现场样品
似乎您只期望实例化其中一个重载,因为只会调用其中一个重载,但编译器显然必须实例化它们中的任何一个,以确定是否可以调用它们中的任何一个,如果是,则使用哪一个。
更正式的答案是,这两个模板都是候选模板,因为您的T
始终可以指向,因此从这个意义上说,两者都是"使用"的:
[C++14: 14.7.1/3]:
除非函数模板专用化已显式实例化或显式专用化,否则当在需要存在函数定义的上下文中引用专用化时,将隐式实例化函数模板专用化。除非调用函数模板显式专用化或显式专用类模板的成员函数,否则在需要默认参数值的上下文中调用函数时,将隐式实例化函数模板或类模板的成员函数的默认参数。
[C++14: 14.7.1/10]:
如果函数模板或成员函数模板专用化以涉及重载解析的方式使用,则会隐式实例化专用化声明 (14.8.3)。
所以,基本上:
我想这是必需的,以便编译器可以执行重载解决?
正确。
但是,您的问题已经源于一种误解,即您的第一个函数模板可以忽略:它不可能。 zzz
不依赖于任何模板参数,因此不涉及 SFINAE;即使涉及 SFINAE,它也无法帮助您处理无效语法。因此,无论您做什么,该代码的格式都是错误的:
template<typename T>
void nil() {zzz}
// g++ -c -std=c++11 -O2 -Wall -pedantic -pthread main.cpp
// main.cpp: In function 'void nil()':
// main.cpp:2:13: error: 'zzz' was not declared in this scope
// void nil() {zzz}
// ^
(现场演示)
话虽如此,在这种情况下不需要诊断;特别是,Visual Studio历来Microsoft默地接受这样的代码:
[C++14: 14.6/8]:
知道哪些名称是类型名称可以检查每个模板的语法。不得对可以生成有效专业化的模板发布诊断。如果无法为模板生成有效的专用化,并且该模板未实例化,则模板格式不正确,无需诊断。如果可变参数模板的每个有效专用化都需要一个空的模板参数包,则该模板格式不正确,无需诊断。如果在非依赖名称中使用的类型在定义模板时不完整,但在完成实例化时已完成,并且如果该类型的完整性影响程序的格式是否正确或影响程序的语义,则程序格式不正确;无需诊断。[..]
在C++11和C++03中也可以找到相同的措辞,因此情况一直如此。因此,您的误解是可以理解的。
顺便说一下,你对虚函数的观察也不完全准确:
[C++14: 14.7.1/11]
:实现不得隐式实例化不需要实例化的函数模板、变量模板、成员模板、非虚拟成员函数、成员类或类模板的静态数据成员。如果虚拟成员函数不会被实例化,则不指定实现是否隐式实例化类模板的虚拟成员函数。在默认参数中使用模板专用化不会导致模板被隐式实例化,除非类模板可能需要其完整类型来确定默认参数的正确性。在函数调用中使用默认参数会导致隐式实例化默认参数中的专用化。
这不是来自内部问题的答案,而是与问题的假设有关:"如果没有实例化第一个重载,我希望不会发生编译器错误,但是我得到了错误。
当然可以吗?那么,为什么这段代码会生成编译器错误呢?
template<typename T>
void nil(T) {zzz}
template<typename T>
void foo(T*) {}
int main()
{
int* blah;
foo(blah);
}
因为nil
未实例化
- 从C++实例化QML
- 设计一个只能由特定类实例化的类(如果可能的话,通过make_unique)
- 如何创建一个空的全局类并在启动时实例化它
- 在两个类中共享相同的函数调用,并在不需要时避免空实例化
- 约束和显式模板实例化
- 为什么包含windows.h会产生语法错误,从而阻止类的实例化?(C2146,C2065)
- 对象实例化调用构造函数的次数太多
- 如何使用非默认构造函数实例化模板化类
- 静态数据成员模板专用化的实例化点在哪里
- 函数模板实例化、替换和重载解析的顺序是什么?
- 无法实例化重载的模板化函数
- 模板实例化失败:编译器选择不正确的重载函数
- 为什么找不到使用命名空间中定义的类型实例化的 std::weak_ptr 的重载运算符==?
- 如何编写模板重载函数,并在模板参数不允许实例化某个类时触发回退
- 重载前模板实例化出错
- 实例化重载的函数模板
- 在使用包含类的动态实例化后调用 c++ 重载运算符 [] 似乎不起作用
- 模板函数重载的实例化
- 在定义上下文或实例化点中,何时进行非依赖名称的重载解析
- GCC 和 Clang 在运算符重载解析期间隐式实例化模板参数