懒惰的enable_if在工作中睡觉?

时间:2012-10-02 23:14:47

标签: c++ templates c++11 sfinae enable-if

根据下面显示的定义,我可以使用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>(); }

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的参数)即使I0。懒惰地评估所述类型的身份将无法拯救你。

不幸的是,我似乎无法使用GCC 4.7.2运行示例,即使将条件修复为I > 0并使用惰性结果(尽管通常我会使用),它仍坚持不终止递归4.8),所以我不能向你保证我的解决方案可以起作用。