【发布时间】:2020-07-10 20:33:37
【问题描述】:
当从非模板上下文引用函数模板时,该标准允许在封闭的命名空间范围声明之后或在翻译单元的末尾实例化函数模板:[temp.point]/1
对于函数模板特化,成员函数模板 特化,或成员函数或静态的特化 类模板的数据成员,如果特化是隐式的 实例化,因为它是从另一个模板中引用的 专业化和引用它的上下文取决于 模板参数,特化的实例化点 是封闭特化的实例化点。 否则,这种特化的实例化点紧跟在命名空间范围声明或定义之后 指专业化。
函数模板的特化,成员函数模板, 或类模板的成员函数或静态数据成员 在翻译单元中有多个实例化点,并且 除了上述实例化点之外,对于任何 这种特殊化在 翻译单元,翻译单元的结尾也被认为是一个 实例化点。 类模板的特化在 翻译单元内的大多数实例化点。一种 任何模板的特化都可能有实例化点 多个翻译单元。如果两个不同的实例化点 根据模板特化赋予不同的含义 单定义规则,程序格式错误,无诊断 必填。
现在考虑这个最小的可重现示例:
#include <iostream>
#include <array>
struct A {};
std::array<char, 2> show(float, A)
{
std::cout << "2\n";
return {};
}
template<typename T>
struct Fun {
decltype(show(0, T{})) b;
};
template <typename T>
void func(T, int c = sizeof(Fun<T>{}.b))
{
show(0, T{});
std::cout << c << '\n';
}
int main()
{
func(A{});
}
char show(int, A)
{
std::cout << "1\n";
return {};
}
GCC 和 Clang 都输出 1 2 (godbolt)。
这里,func<A> 的实例化(在main 中触发)有两个实例化点:一个紧跟在main 之后(因此在第二个show 之前),另一个在翻译单元的末尾。第一个1 表示编译器在翻译单元的末尾实例化func<A>。但是,默认参数sizeof(Fun<T>{}.b) 导致Fun<A> 被实例化,第二个2 表明Fun<A> 在第二个show 之前实例化。
现在,默认参数的实例化点被指定为func<A>:[temp.point]/2
如果类模板的函数模板或成员函数是 以使用默认参数定义的方式调用 那个函数模板或成员函数,要点 默认参数的实例化是 函数模板或成员函数特化。
嗯...这似乎表明这两个数字应该相同。
我觉得我在这里遗漏了一些东西。有没有我碰巧忽略的细节?还是我犯了错误?
【问题讨论】:
标签: c++ templates language-lawyer instantiation name-lookup