Reputation: 4845
I have that piece of code (which is a minimal reproduced from a way larger project).
#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;
}
It fails with gcc 9.2 with the following error :
In instantiation of 'constexpr const auto poly_gcd, myint<0>>::val':
recursively required from 'constexpr const auto poly_gcd, myint<2> >::val'
required from 'constexpr const auto poly_gcd, myint<4> >::val'
:70:56: required from here
:27:27: error: incomplete type
'poly_gcd_reduce_helper, void>' used in nested name specifierstatic constexpr auto val = poly_gcd_reduce_helper::val;
Apparently the compiler tries to instanciate poly_gcd_reduce_helper, void> even if I have mutually exclusive implementations of poly_gcd_reduce_helper depending on the sign of the first template argument.
I must admit I don't know what to do now.
Upvotes: 2
Views: 353
Reputation: 14563
There's no need to wrap an integer in a special type, this can all be dramatically simplified:
#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
Upvotes: 0
Reputation: 172904
In the specialization of poly_gcd_reduce_helper
, given the usage PA::sign() > 0
, sign()
is expected to be a static member function; while myint::sign()
is a non-static member function. Then for myint
the specialization of poly_gcd_reduce_helper
would never be selected.
Change it to
static constexpr int sign() {
if constexpr (p > 0)
return 1;
else if constexpr (p == 0)
return 0;
else
return -1;
}
Upvotes: 3