【问题标题】:Implicit conversion operator T() with template overloads using std::enable_if fail to compile使用 std::enable_if 进行模板重载的隐式转换运算符 T() 无法编译
【发布时间】:2019-02-05 04:09:53
【问题描述】:

我正在用 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);

【问题讨论】:

  • 问题是你用不同的默认参数声明了两次相同的成员模板。该错误发生在任何实例化之前,因此甚至不查看默认参数。要解决,请将enable_if_t 移出参数并使其成为运算符的返回类型。
  • 我更新了模板,但现在我得到了无效的 static_cast。我会用我尝试过的方法更新问题。
  • Aww 抱歉,您不能这样做,这会创建一个未推断的上下文。我会用另一种方法来回答。

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


【解决方案1】:

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

解决这个问题的第一个动力是将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 ...

另一个模板应该保持原样。

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

【讨论】:

  • 或者在两个重载中使用std::enable_if_t&lt;std::is_floating_point_v&lt;T&gt;, bool&gt; = true作为非类型模板参数。
【解决方案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);
}

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-01-21
    • 2012-02-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多