Следующий код:
#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);
}
не может скомпилироваться с g ++ - 5.4 или g ++ - 7.4 (пробовал -std = c ++ 14, -std = c ++ 17) с тем, что кажетсяошибка рекурсии шаблона без дна:
<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
Однако, если я заменим EnumT
на int
или перечисление с областью действия, все скомпилируется нормально.Также обратите внимание на ключевое слово explicit
, закомментированное во втором конструкторе.Если я раскомментирую его, то эта версия с EnumT
тоже будет компилироваться.
Кто-нибудь может объяснить, что именно происходит?Заранее спасибо.