使用std :: enable_if的带有模板重载的隐式转换运算符T()无法编译

时间:2019-02-05 04:09:53

标签: c++ templates c++17 sfinae

我正在用C ++ 17编写一个类,我想要用于浮点类型以及某些自定义类型的重载转换运算符。这是可重现的示例。我还需要使用模板添加更多的转换,但是如果我可以解决这些转换,其余的应该都差不多。

class A {
};

class B : public A {
};

class C: public A {
};

class Missing {
 public:
  Missing() {}
  Missing(Missing &) = default;

  template<typename T,typename=typename std::enable_if_t<std::is_floating_point_v<T>, T>>
  explicit constexpr operator T() const {
    return static_cast<T>(NAN);
  }

  template<typename T, class = typename std::enable_if_t<std::is_base_of_v<A, T>, T>>
  explicit operator T() const {
    return T();
  }


};

但是在使用带有std = c ++ 17标志的gcc 8.2进行编译时,出现以下错误:

<source>:25:12: error: 'template<class T, class> Missing::operator T() const' cannot be overloaded with 'template<class T, class> constexpr Missing::operator T() const'

   explicit operator T() const {

            ^~~~~~~~

<source>:20:22: note: previous declaration 'template<class T, class> constexpr Missing::operator T() const'

   explicit constexpr operator T() const {

                      ^~~~~~~~

Compiler returned: 1

我认为使用enable_if可以防止运算符针对同一类型进行重载,但是看起来编译器在第一遍中并没有查看enable_if。我不确定我的语法是否正确。任何帮助,将不胜感激。现在已经有一段时间了。


更新

试图将运算符更新为

  template<typename T>
  constexpr explicit operator std::enable_if_t<std::is_floating_point_v<T>, T>() const {
    return static_cast<T>(NAN);
  }

  template<typename T>
  explicit operator std::enable_if_t<std::is_base_of_v<A, T>, T>() const {
    return T();
  }

但是现在,在尝试将类强制转换为浮动类型时:

int main() {
    Missing m;
    float a = static_cast<float>(m);
}

我得到一个错误:

<source>:34:35: error: invalid static_cast from type 'Missing' to type 'float'

     float a = static_cast<float>(m);

2 个答案:

答案 0 :(得分:2)

问题是您用不同的默认参数两次声明了相同的成员模板。该错误发生在任何实例化之前,因此甚至不查看默认参数。

解决此问题的第一个冲动是将enable_if_t移出参数,并使其成为运算符的返回类型:

template<typename T>
explicit constexpr operator std::enable_if_t<std::is_floating_point_v<T>, T>>() const ...

但这不起作用,因为T现在是无法推论的上下文。

因此,使两个模板不同的另一种方法是向其中的一个 添加一个带有默认值的虚拟参数。

template<typename T,
         typename = std::enable_if_t<std::is_floating_point_v<T>, T>,
         bool = true>
explicit constexpr operator T() const ...

其他模板应保留不变。

由于两个模板具有不同数量的模板参数,因此不再认为它们相同。

答案 1 :(得分:2)

另一种方法是将推导的模板参数定义为默认指针:

template
<
  typename T, 
  std::enable_if_t<std::is_floating_point_v<T>>* = nullptr
>
explicit constexpr operator T() const {
  return static_cast<T>(NAN);
}

我发现这是选择启用方法,运算符和构造函数的简洁可靠的方法。