С приведенным ниже определением я могу позвонить 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>(); }
Когда вы объявляете функцию или шаблон функции, например, ret foo(A, B, C);
или равнодушно как auto foo(A, B, C) -> ret;
тогда foo
это относится к только что объявленной сущности, которая находится вне области действия до так называемого декларатора. В вашем конкретном случае тип возвращаемого значения (будь то поздний тип возвращаемого значения или нет) всегда является частью объявления.
Это означает, что в вашей последней декларации имя qget
в возвращаемом типе может ссылаться на предыдущую декларацию (случай для I==0
) но никогда не может ссылаться на текущую декларацию. Вот почему qget<0>
а также qget<1>
найдены, но qget<2>
нет: при попытке сформировать тип возвращаемого значения последнего, qget<1>
не найден, потому что первая декларация является SFINAE’d, как и предполагалось, а вторая декларация является текущей декларацией, а не в области видимости. Ошибка приводит к SFINAE.
Мое обычное решение, когда это происходит (что я должен сказать, не так часто), заключается в использовании struct
(как деталь реализации), потому что все функции-члены (и шаблоны функций-членов) объявляются внутри определения класса, начиная с открывающей скобки.
При этом вы все равно столкнетесь с трудностями, потому что даже если вы используете lazy_enable_if_c
вы все еще нетерпеливо вычисляете тип qget<I - 1>()
(в качестве параметра для lazy_enable_if_c
) даже когда I
является 0
, Ленивая оценка идентичности указанного типа не спасет вас.
К сожалению, я не могу получить пример, работающий с использованием GCC 4.7.2, который настаивает на том, чтобы не завершать рекурсию даже при исправлении условия в I > 0
и используя ленивый результат (хотя обычно я использую 4.8), поэтому я не могу обещать вам, что мое решение может быть выполнено.
Других решений пока нет …