Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/154.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 关于模板实例化点的几个问题_C++_Templates - Fatal编程技术网

C++ 关于模板实例化点的几个问题

C++ 关于模板实例化点的几个问题,c++,templates,C++,Templates,首先,一些标准的引用段落 如果模板专用化X在依赖于某个周围模板Y的模板参数的上下文中引用,则给定的实例化点取决于Y的实例化点。 如果X是函数模板专用化,则实例化点是Y的实例化点。 如果X是一个类模板专门化,那么实例化点就在Y的实例化点之前 否则,给定的实例化点将绑定到名称空间范围声明/定义(D)的位置,其中包含引用X的语句。 如果X是函数模板专用化,则实例化点紧跟在D之后。 如果X是一个类模板专门化,那么实例化点就在D之前 这里有一些代码 #include <iostream> te

首先,一些标准的引用段落

如果模板专用化X在依赖于某个周围模板Y的模板参数的上下文中引用,则给定的实例化点取决于Y的实例化点。
如果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

在#3
auto 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说明符的隐式实例化>朋友

因此在#3
auto 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;}