关于模板实例化的一些问题

时间:2019-10-18 12:11:08

标签: c++ templates

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

  

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

因此,根据上述规则,在实例化类data<int, 0>时,实例化点位于#1。

然后show<T,N>取决于模板类数据的模板参数。因此,show<int,0>的实例化点在#2。

然后add_state<N>取决于模板功能展示的模板参数。因此,根据规则,add_state<0>的实例化点在#3。

已在#3 auto call(state<0>)处定义了call(state<0>{}),但实际上,编译器报告的错误如下:

c语:

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>{});
                 ^ 

为什么?我是否了解实例化点有一些错误? 如果没有,为什么编译器会报告这些错误?

4 个答案:

答案 0 :(得分:2)

根据[temp.inst]/2.1,当隐式实例化类模板时,仅实例化好友声明:

  

类模板专门化的隐式实例化导致声明的隐式实例化,而不是类成员的定义,默认参数或noexcept-specifiers的隐式实例化。函数,成员类,作用域成员枚举,静态数据成员,成员模板和 friends

因此,在#3,auto call(state<N>)仅被声明。而且,通过普通的非限定名称查找找不到此声明。

尽管如此,我认为这不会使您的代码形式上不正确。您的代码太奇怪了,以至于标准委托方成员或编译器实现者可能从未考虑过这种情况:通常在类中定义了内联好友函数,该类使该好友函数可通过ADL(自变量依赖名称查找)可见。当然,这也是编译器所期望的。

因此,在call(state<0>{})内的main处,ADL在call的定义内找到了state的声明,并且编译器只是不考虑寻找一个某种无关的类add_state中此函数的潜在定义。因此无法推论auto

答案 1 :(得分:0)

我对这件事不太自信,但是希望这可以证明是有用的,我提出了另一个可行的例子,除了已经建议的例子:

#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;
}

我不确定这是否有帮助。但是我希望如此,就像我一样,对一个好的解释感兴趣。

答案 2 :(得分:0)

您的问题在这里:

shopt -s nullglob
files=( /home/methuselah/$filePattern )
for file in "${files[@]}"; do
    # something to be done here
done

编译器绝对无法告知template<int N> struct state { friend auto call(state<N>);//<--no way of telling return type ! }; 函数返回什么并且必须放弃。 该修复程序也很明显,只需对其进行一些操作即可,例如:

call

答案 3 :(得分:-2)

如果使用int而不是auto出现错误:

main.cpp:15: undefined reference to `call(state<0>)'
collect2.exe: error: ld returned 1 exit status

{return N;}添加到friend int call(state<N>)时,效果很好。 然后将int换回auto,它也可以工作。