C++ 关于模板实例化点的几个问题
首先,一些标准的引用段落 如果模板专用化X在依赖于某个周围模板Y的模板参数的上下文中引用,则给定的实例化点取决于Y的实例化点。C++ 关于模板实例化点的几个问题,c++,templates,C++,Templates,首先,一些标准的引用段落 如果模板专用化X在依赖于某个周围模板Y的模板参数的上下文中引用,则给定的实例化点取决于Y的实例化点。 如果X是函数模板专用化,则实例化点是Y的实例化点。 如果X是一个类模板专门化,那么实例化点就在Y的实例化点之前 否则,给定的实例化点将绑定到名称空间范围声明/定义(D)的位置,其中包含引用X的语句。 如果X是函数模板专用化,则实例化点紧跟在D之后。 如果X是一个类模板专门化,那么实例化点就在D之前 这里有一些代码 #include <iostream> te
如果X是函数模板专用化,则实例化点是Y的实例化点。
如果X是一个类模板专门化,那么实例化点就在Y的实例化点之前 否则,给定的实例化点将绑定到名称空间范围声明/定义(D)的位置,其中包含引用X的语句。
如果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>{});
}
#包括
模板
结构状态{
朋友自动呼叫(状态);
};
模板
结构添加状态{
朋友自动呼叫(状态){
返回N;
}
};
模板
T show(){
添加_状态d;
返回T{};
}
模板
类数据{
公众:
tc=show();
};
#1,#3,#2
int main(){
数据t;
调用(状态{});
}
因此,根据上述规则,当实例化class数据时,实例化点位于#1
然后,show
取决于模板类数据的模板参数。因此,show
的实例化点位于#2
然后,add_state
取决于模板函数show的模板参数。因此根据规则,add_state
的实例化点位于#3
在#3auto call(state)
已定义时,应链接call(state{})
,但事实上,编译器报告错误如下:
叮当声:
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.
main.cpp:24:2:错误:具有推断返回类型的函数“call”在定义之前无法使用
调用(状态{});
^
main.cpp:4:14:注意:此处声明了“调用”
朋友自动呼叫(状态);
^
生成1个错误。
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>{});
^
main.cpp:在函数“int main()”中:
main.cpp:24:17:错误:在扣除“自动”之前使用“自动调用(状态)”
调用(状态{});
^
为什么??我对实例化点的理解有错误吗?
如果没有,为什么编译器会报告这些错误?如果使用int
而不是auto
得到错误:
main.cpp:15: undefined reference to `call(state<0>)'
collect2.exe: error: ld returned 1 exit status
main.cpp:15:call(state)的未定义引用
collect2.exe:错误:ld返回了1个退出状态
当将{return N;}
添加到友元int调用(state)
时,效果很好。
然后将int
替换回auto
,它也可以工作。我自己对这件事不是很有信心,但希望这可能会有用,我把另一个工作示例放在一起,而不是已经提出的示例:
#include <iostream>
// forward declaration of the
// add_state template
template<int>
struct add_state;
template<int N>
struct state {
// Note: we generate the state here
// so that the compiler will see the
// definition of the call function
add_state<N> t;
friend auto call(state<N>);
};
template<int N>
struct add_state {
friend auto call(state<N>) {
return N;
}
};
int main() {
auto val = call(state<42>{});
std::cout << val << std::endl;
return 0;
}
#包括
//未来宣言
//添加状态模板
模板
结构添加状态;
模板
结构状态{
//注意:我们在这里生成状态
//这样编译器就可以看到
//调用函数的定义
添加_状态t;
朋友自动呼叫(状态);
};
模板
结构添加状态{
朋友自动呼叫(状态){
返回N;
}
};
int main(){
auto val=调用(状态{});
std::cout您的问题是:
template<int N>
struct state {
friend auto call(state<N>);//<--no way of telling return type !
};
根据,隐式实例化类模板时,仅实例化好友声明:
类模板专门化的隐式实例化会导致声明的隐式实例化,但不会导致类成员函数、成员类、作用域成员枚举、静态数据成员、成员模板和的定义、默认参数或noexcept说明符的隐式实例化>朋友
因此在#3auto call(state)
中只声明了该声明。而且,通过普通的非限定名称查找无法找到该声明
尽管如此,我并不认为这会使您的代码格式错误。您的代码非常奇怪,可能标准委员会成员或编译器实现者从未考虑过这种情况:通常内联友元函数是在类中定义的,通过ADL使友元函数可见(依赖于参数的名称查找)。这当然也是编译器的例外
所以在调用时(状态{})
在main
中,ADL在state
的定义中找到了call
的声明,编译器只是不考虑在不相关的类add\u state
中寻找该函数的潜在定义。因此它无法推断auto
add{return N;}到哪个调用?您是否将函数调用的声明更改为定义?因为show
是一个函数模板,它重用#1,并且#3在该调用之前。请注意:有状态元编程已由委员会批准。函数模板专门化在翻译单元的末尾也有一个实例化点。如果show
在翻译单元末尾实例化,call(state)
的定义将在call(state{})中使用之后;
[temp.point]/5还禁止“两个不同的实例化点[to]根据一个定义规则赋予模板专门化不同的含义”,虽然我不知道这是否包括这个场景。如果您使用show
的占位符返回类型强制实例化主体,@davishering是的,#1和#2是相同的poiYes,那么GCC和Clang都可以很好地编译它。据我所知,如果只有类模板专门化,而没有函数,它总是可以工作的实例化序列中的mplate专门化,这就是为什么我假设
friend auto call(state<N>) {return N;}