The following code:
#include <iostream>
#include <type_traits>
enum EnumT{Invalid = 0, Float, N_Types};//enum triggers the problem; works fine with ints
template<typename T, EnumT id_>
struct X
{
template<EnumT id = id_,
std::enable_if_t<(id != Float)> * = nullptr>
constexpr explicit X(T v): val_(v)
{
std::cout<<"cnstr..."<<id<<"\n";
}
template<EnumT id = id_,
std::enable_if_t<(id == Float)> * = nullptr>
constexpr /*explicit*/ X(float v): val_(v)
{
std::cout<<"cnstr..."<<id<<"\n";
}
template<typename OUT,
EnumT id = id_,
std::enable_if_t<(id == Float)> * = nullptr>
explicit operator OUT() const
{
std::cout<<"conv. op....\n";
return static_cast<float>(val_);
}
private:
T val_;
};
using Y = X<float, Float>;
bool operator==(Y const &lhs, Y const &rhs){
return static_cast<float>(lhs) == static_cast<float>(rhs);
}
fails to compile with g++-5.4 or g++-7.4 (tried -std=c++14, -std=c++17) with what seems to be a bottomless template recursion error:
<source>: In substitution of 'template<EnumT id, std::enable_if_t<(id == Float), void>* <anonymous> > constexpr X<float, Float>::X(float) [with EnumT id = Float; std::enable_if_t<(id == Float), void>* <anonymous> = <missing>]':
<source>:17:48: recursively required by substitution of 'template<EnumT id, std::enable_if_t<(id == Float), void>* <anonymous> > constexpr X<float, Float>::X(float) [with EnumT id = Float; std::enable_if_t<(id == Float), void>* <anonymous> = <missing>]'
<source>:17:48: required by substitution of 'template<EnumT id, std::enable_if_t<(id == Float), void>* <anonymous> > constexpr X<float, Float>::X(float) [with EnumT id = Float; std::enable_if_t<(id == Float), void>* <anonymous> = <missing>]'
<source>:26:48: required by substitution of 'template<class OUT, EnumT id, std::enable_if_t<(id == Float), void>* <anonymous> > X<float, Float>::operator OUT<OUT, id, <enumerator> >() const [with OUT = float; EnumT id = Float; std::enable_if_t<(id == Float), void>* <anonymous> = <missing>]'
<source>:39:34: required from here
<source>:17:48: fatal error: template instantiation depth exceeds maximum of 900 (use '-ftemplate-depth=' to increase the maximum)
17 | std::enable_if_t<(id == Float)> * = nullptr>
| ^~~~~~~
compilation terminated.
Compiler returned: 1
However, if I replace EnumT with either int or a scoped enumeration, everything compiles fine. Also observe the explicit keyword commented out in the 2nd constructor. If I uncomment it then this version with EnumT also compiles fine.
Anyone could explain what exactly is going on? Thanks in advance.