此代码片段:
namespace ns
{
struct last;
struct first
{
typedef last next;
};
template <typename T>
struct chain
{
chain<typename T::next> next;
};
template <>
struct chain<last>
{
};
}
using namespace ns;
template <typename T>
void f(const T& x) // #1
{
f(x.next);
}
void f(const chain<last>&) // #2
{
}
int main()
{
f(chain<first>());
}
在Comeau上给出以下错误,在GCC上出现一个非常类似的错误:
"ComeauTest.c", line 27: error: class "ns::chain<ns::last>" has no member "next"
f(x.next);
^
detected during:
instantiation of "void f(const T &) [with T=ns::chain<ns::last>]"
at line 27
instantiation of "void f(const T &) [with T=ns::chain<ns::first>]"
at line 36
但如果在#2
之前定义#1
,或在last
之外声明ns
,则会进行编译。
对此有何解释?
答案 0 :(得分:3)
案例1)
template <typename T>
void f(const T& x) // #1
{
f(x.next); //where's f ??
}
void f(const chain<last>&) // #2
{
}
您需要确保#2
是#1
的模板专精,方法是指定template<>
以上的void f(const chain<last>&) // #2
没有template<>
void f(const chain<last>&)
会被解释为f
的重载。因此,由于缺少f(x.next);
的声明,对void f(const chain<last>&)
的调用将会形成错误。
在函数模板上面添加重载声明会使代码编译。
解决方案:
1)
template <typename T>
void f(const T& x) // #1
{
f(x.next); //hmm specialized version down there.
}
template<>
void f(const chain<last>&) // #2
{
}
2)
void f(const chain<last>&); // #0
template <typename T>
void f(const T& x) // #1
{
f(x.next); //hmm I can see #0, call #2
}
void f(const chain<last>&) // #2
{
}
案例2)
void f(const chain<last>&) // #2
{
}
template <typename T>
void f(const T& x) // #1
{
f(x.next); // found!!
}
答案 1 :(得分:0)
鉴于
template <typename T>
void f(const T& x) // #1
{
f(x.next);
}
void f(const chain<last>&) // #2
{
}
...对第一个f
主体中f
的调用无法调用第二个f
,因为此时第二个f
不可见。
因此,如果您进入第一个next
,那么它将递归到第一个错误。 :-)我在这里谈论编译时间递归,只要f
属于main
尚未实例化的类型。
int main()
{
f(chain<first>());
}
中的来电,......
f
...必须调用第一个chain<first>
,因为f
与第二个f(
的参数类型不匹配。
这会产生chain<last>
)
类型的递归调用f
arg。在尝试为参数类型chain<last>
实例化next
时,您会收到错误,因为chain<last>
中没有last
属性。
关于将{{1}}的声明放在全局命名空间中时显然编译OK的代码,我不知道。你确定吗?注意:我没有尝试使用真正的编译器。
干杯&amp;第h。,