首页 > 解决方案 > C++ (14/17) 使用枚举作为非类型模板参数时出现奇怪的无底模板递归错误

问题描述

以下代码:

#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也可以很好地编译。

任何人都可以解释到底发生了什么?提前致谢。

标签: c++c++14c++17enumerationtemplate-specialization

解决方案


推荐阅读