Оператор неявного преобразования T () с шаблонными перегрузками, использующими std :: enable_if, не компилируется - PullRequest
0 голосов
/ 05 февраля 2019

Я пишу класс на 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();
  }


};

Однако при компиляции с gcc 8.2 с флагом std = c ++ 17,Я получаю следующую ошибку:

<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 голосов
/ 05 февраля 2019

Другой способ состоит в том, чтобы определить выведенный аргумент шаблона как указатель по умолчанию:

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

Я считаю, что это краткий и надежный способ необязательного включения методов, операторов и конструкторов.

0 голосов
/ 05 февраля 2019

Проблема в том, что вы объявляете один и тот же шаблон элемента дважды с разными аргументами по умолчанию.Ошибка происходит перед любой реализацией, поэтому аргументы по умолчанию даже не рассматриваются.

Первым импульсом, который решил бы это, было бы выдвинуть 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 ...

Другой шаблон следует оставить как есть.

Поскольку два шаблона имеют разное количество параметров шаблона, они больше не считаются идентичными.

...