C ++ (14/17) Странная бездонная ошибка рекурсии шаблона при использовании перечислений в качестве нетипичных параметров шаблона - PullRequest
3 голосов
/ 06 июня 2019

Следующий код:

#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 тоже будет компилироваться.

Кто-нибудь может объяснить, что именно происходит?Заранее спасибо.

...