根据下面显示的定义,我可以使用G ++(4.7.2)拨打qget<0>()
或qget<1>()
,但qget<2>
或“更高”会因no matching function
而失败错误。与此同时,Clang ++(3.2)也失败了。我使用 lazy enable_if作为最后的手段;虽然我不认为我应该需要它。我知道代码看起来有点奇怪,但任何人都可以看到错误的来源? (Boost提供了enable_if类。)
template <typename T> struct Tid { typedef T type; };
template <unsigned I>
typename enable_if_c<(I==0),double>::type
qget()
{ return 0.0; }
template <unsigned I>
typename lazy_enable_if_c<(I!=0), Tid<decltype(qget<I-1>())>>::type
qget()
{ return qget<I-1>(); }
答案 0 :(得分:3)
当您将函数或函数模板声明为例如ret foo(A, B, C);
或者auto foo(A, B, C) -> ret;
无关紧要,那么引用刚刚声明的实体的foo
直到所谓的声明者之后才在范围内。在您的特定情况下,返回类型(无论是否是延迟返回类型)始终是声明者的一部分。
这意味着在您的上一个声明中,返回类型中的名称qget
可能引用前一个声明(I==0
的情况),但可能永远不会引用当前声明。这就是找到qget<0>
和qget<1>
的原因,但qget<2>
不是:当尝试形成后者的返回类型时,找不到qget<1>
,因为第一个声明是SFINAE按预期排除,第二个声明是当前声明而不是范围。该错误导致SFINAE。
我发生这种情况的常用解决方案(我不得不经常说)是使用struct
(作为实现细节),因为所有成员函数(和成员函数)模板)在类的定义中声明,来自开头括号。
话虽如此,你仍然会遇到麻烦,因为即使你使用lazy_enable_if_c
,你仍然急切地计算qget<I - 1>()
的类型(作为lazy_enable_if_c
的参数)即使I
为0
。懒惰地评估所述类型的身份将无法拯救你。
不幸的是,我似乎无法使用GCC 4.7.2运行示例,即使将条件修复为I > 0
并使用惰性结果(尽管通常我会使用),它仍坚持不终止递归4.8),所以我不能向你保证我的解决方案可以起作用。