【发布时间】:2019-10-18 12:11:08
【问题描述】:
首先,一些标准的引用段落
如果在依赖于某个周围模板 Y 的模板参数的上下文中引用模板特化 X,则给定的实例化点取决于 Y 的实例化点。
如果 X 是函数模板特化,则实例化点是 Y。
如果 X 是类模板特化,则实例化点就在 Y 的实例化点之前。否则,给定的实例化点与包含引用 X 的语句的命名空间范围声明/定义 (D) 的位置相关联。
如果 X 是函数模板特化,则实例化点紧接在 D 之后。
如果 X 是类模板特化,则实例化点就在 D 之前。
这里有一些代码
#include <iostream>
template<int N>
struct state {
friend auto call(state<N>);
};
template<int N>
struct add_state {
friend auto call(state<N>) {
return N;
}
};
template<typename T, int N>
T show() {
add_state<N> d;
return T{};
}
template<typename T,int N>
class data {
public:
T c = show<T,N>();
};
#1,#3,#2
int main() {
data<int, 0> t;
call(state<0>{});
}
所以,根据上面的规则,当实例化类data<int, 0>时,那么实例化的点就在#1。
那么show<T,N> 依赖于模板类数据的模板参数。所以show<int,0> 的实例化点在#2。
那么add_state<N> 依赖于模板函数show 的模板参数。所以根据规则,add_state<0> 的实例化点在#3。
在#3 auto call(state<0>)已经定义,call(state<0>{})应该被链接,但实际上编译器报错如下:
叮当声:
main.cpp:24:2: error: function 'call' with deduced return type cannot be used before it is defined
call(state<0>{});
^
main.cpp:4:14: note: 'call' declared here
friend auto call(state<N>);
^
1 error generated.
g++:
main.cpp: In function ‘int main()’:
main.cpp:24:17: error: use of ‘auto call(state<0>)’ before deduction of ‘auto’
call(state<0>{});
^
为什么?我对实例化点的理解是否有一些错误? 如果不是,为什么编译器会报告这些错误?
【问题讨论】:
-
由于
show是一个函数模板,它重用了#1,而#3在它之前。 -
警告:有状态元编程已被委员会condemned。
-
函数模板特化在翻译单元[temp.point]/5的末尾也有一个实例化点。如果
show<int,0>在翻译单元的末尾被实例化,call(state<0>)的定义将在call(state<0>{});的使用之后。 [temp.point]/5 还禁止“两个不同的实例化点[to]根据单定义规则赋予模板特化不同的含义”,虽然我不知道这是否包括这个场景。 -
如果您使用
show的占位符返回类型来强制实例化主体,则 GCC 和 Clang 都可以正常编译:godbolt.org/z/jEuQ_k -
@DavisHerring 是的,#1 和 #2 是同一个 poi