2

使用下面显示的定义,我可以调用qget<0>()qget<1>()使用 G++ (4.7.2),但qget<2>或“更高”将失败并出现no matching function错误。同时,Clang++ (3.2) 中的任何一个都失败了。我使用了惰性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>(); }
4

1 回答 1

3

当您将函数或函数模板声明为 egret foo(A, B, C);或无关紧要地声明为auto foo(A, B, C) -> ret;foo,引用刚刚声明的实体的 直到所谓的声明符之后才在范围内。在您的特定情况下,返回类型(无论是否为后期返回类型)始终是声明符的一部分。

这意味着在您的最后一个声明qget中,返回类型中的名称可能引用前一个声明( 的情况I==0),但可能永远不会引用当前声明。这就是为什么qget<0>andqget<1>被发现,但qget<2>不是:当试图形成后者的返回类型时,qget<1>因为第一个声明按预期被 SFINAE 淘汰,而第二个声明是当前声明而不是在范围内,所以没有找到。该错误导致 SFINAE。

发生这种情况时我通常的解决方案(我不得不说并不经常)是使用 a struct(作为实现细节),因为所有成员函数(和成员函数模板)都是在类的定义中声明的,从左大括号开始上。

话虽如此,您仍然会遇到障碍,因为即使您在使用lazy_enable_if_c时,您仍然急切地计算qget<I - 1>()(作为 的参数lazy_enable_if_c)的类型,即使 is 时I也是如此0。懒惰地评估所述类型的身份不会拯救你。

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

于 2012-10-03T06:19:14.430 回答