Есть ли способ рекурсивно использовать Руководство по дедукции шаблонов классов? (Тьюринг завершен) - PullRequest
0 голосов
/ 15 января 2019

Я играю с руководством по вычету шаблона класса и пытаюсь использовать его рекурсивно. Но я не могу получить следующий код для компиляции

#include <type_traits>

template<int N>
using int_const = std::integral_constant<int,N>;

template<int N>
struct Foo{
    constexpr static int value = N;

    template<int C>
    constexpr Foo(int_const<C>){};
};

Foo(int_const<0>) -> Foo<1>;

template<int N>
Foo(int_const<N>) -> Foo<N*(Foo{int_const<N-1>{}}.value)>;

int main(){
    return Foo{int_const<5>{}}.value;
}

Это ошибка:

<source>: In substitution of 'template<int N> Foo(int_const<N>)-> Foo<(N * >     Foo{std::integral_constant<int, (N - 1)>{}}.value)> [with int N = -894]':
<source>:17:51:   recursively required by substitution of 'template<int N> Foo(int_const<N>)-> Foo<(N * Foo{std::integral_constant<int, (N - 1)>{}}.value)> [with int N = 4]'
<source>:17:51:   required by substitution of 'template<int N> Foo(int_const<N>)-> Foo<(N * Foo{std::integral_constant<int, (N - 1)>{}}.value)> [with int N = 5]'
<source>:20:30:   required from here
<source>:17:1: fatal error: template instantiation depth exceeds maximum of 900 (use -ftemplate-depth= to increase the maximum)
 Foo(int_const<N>) -> Foo<N*(Foo{int_const<N-1>{}}.value)>;
 ^~~

компиляция прекращена.

Ответы [ 2 ]

0 голосов
/ 16 января 2019

работает следующий код:

#include <type_traits>

template<int N>
using int_const = std::integral_constant<int,N>;

template<int N>
struct Foo{
    constexpr static int value = N;

    template<int C>
    constexpr Foo(int_const<C>){};
};

template<int N>
constexpr auto previous_foo(){
    if constexpr (N<=0){
        return 1;
    }
    else {
        return decltype(Foo{int_const<N-1>{}})::value;
    }
 }

template<int N>
Foo(int_const<N>) -> Foo<(N>0)?N*previous_foo<N>():1>;


int main(){
    return Foo{int_const<5>{}}.value;
}
0 голосов
/ 15 января 2019

Вам нужен вспомогательный шаблон:

template<int N>
struct foo_helper
{ static constexpr int value = N * Foo{int_const<N-1>{}}.value; };
template<>
struct foo_helper<0>
{ static constexpr int value = 1; };

С этим (и только) руководством по выводу:

template<int C>
Foo(int_const<C>)
-> Foo<foo_helper<C>::value>
;

Live demo с Foo{int_const<5>{}}.value, правильно оцененнымдо 120.

Почему это так?

Поскольку при следующем руководстве по выводу

template<int N>
Foo(int_const<N>) -> Foo<N*(Foo{int_const<N-1>{}}.value)>;

при запуске CTAD учитываются все направляющие;даже если вы предоставили более специализированное руководство (Foo<0>), это рекурсивное руководство явно специализировано и Foo{int_const<N-1>{}} в конечном итоге становится специализированным для N=0, следовательно, для бесконечной рекурсии.

Введение уровня косвенности,foo_helper нарушает эту бесконечную рекурсию: вы можете специализировать класс, а не руководство по выводам.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...