Неполный тип, используемый в описателе вложенного имени с std enable_if - PullRequest
2 голосов
/ 29 января 2020

У меня есть этот кусок кода (минимальный, воспроизведенный из более крупного проекта).

#include <type_traits>    
template<typename PA, typename E = void>
struct poly_gcd_reduce_helper;

template<typename PA>
struct poly_gcd_reduce_helper<PA, typename std::enable_if<(PA::sign() > 0)>::type>
{
    static constexpr auto val = PA{};
};

template<typename PA>
struct poly_gcd_reduce_helper<PA, typename std::enable_if<(PA::sign() <= 0)>::type>
{
    static constexpr auto val = -PA{};
};

template<typename PA, typename PB>
struct poly_gcd 
{
    static constexpr auto val = poly_gcd<PB, decltype(PA{} -(PA{} / PB{}) * PB {})>::val;
};

template<typename PA>
struct poly_gcd<PA, typename PA::zero_type> 
{
    static constexpr auto val = poly_gcd_reduce_helper<PA>::val;
};

template<int p>
struct myint{
    static constexpr int val = p;
    using zero_type = myint<0>;
    constexpr int sign() const {
        if constexpr (p > 0)
            return 1;
        else if constexpr (p == 0)
            return 0;
        else
            return -1;
    }

    constexpr auto operator-() const {
        return myint<-p>{};
    }
};

template<int a, int b>
static constexpr auto operator/(myint<a> aa, myint<b> bb)
{
    return myint<a / b>{};
}
template<int a, int b>
static constexpr auto operator*(myint<a> aa, myint<b> bb)
{
    return myint<a * b>{};
}
template<int a, int b>
static constexpr auto operator-(myint<a> aa, myint<b> bb)
{
    return myint<a - b>{};
}
template<int a, int b>
static constexpr auto operator+(myint<a> aa, myint<b> bb)
{
    return myint<a + b>{};
}

int main() {
    constexpr auto zou = poly_gcd<myint<2>, myint<4>>::val;
}

Ошибка при g cc 9.2 со следующей ошибкой:

В экземпляре 'constexpr const auto poly_gcd, myint <0 >> :: val':
рекурсивно требуется от 'constexpr const auto poly_gcd, myint <2>> :: val'
требуется от 'constexpr const auto poly_gcd, myint <4>> :: val'
: 70: 56: требуется отсюда
: 27: 27: ошибка: неполный тип
'poly_gcd_reduce_helper, void>', используемый в описателе вложенного имени

stati c constexpr auto val = poly_gcd_reduce_helper :: val;

Очевидно, компилятор пытается создать экземпляр poly_gcd_reduce_helper, void>, даже если у меня есть взаимоисключающие реализации poly_gcd_reduce_helper в зависимости от знака первого аргумента шаблона.

Должен признать, я не знаю, что делать сейчас.

Ответы [ 2 ]

3 голосов
/ 29 января 2020

В специализации poly_gcd_reduce_helper, учитывая использование PA::sign() > 0, ожидается, что sign() будет функцией-членом stati c; в то время как myint::sign() не является статической c функцией-членом. Тогда для myint специализация poly_gcd_reduce_helper никогда не будет выбрана.

Измените ее на

static constexpr int sign() {
    if constexpr (p > 0)
        return 1;
    else if constexpr (p == 0)
        return 0;
    else
        return -1;
}

LIVE

0 голосов
/ 29 января 2020

Нет необходимости заключать целое число в специальный тип, все это может быть значительно упрощено:

#include <iostream>
#include <type_traits>

using namespace std;

template<int VA, int VB>
struct poly_gcd { 
    static constexpr auto val = poly_gcd<VB, VA-(VA/VB)*VB>::val;
};

template<int VA>
struct poly_gcd<VA, 0> {
    static constexpr int val = (VA < 0) ? -VA : VA;
};

int main() {
    constexpr auto zou = poly_gcd<5,10>::val;
    cout << "zou: " << zou << endl;
}

╰─▸ ./test
zou: 2

...