Выберите реализацию шаблонного оператора

#c #templates

#c #шаблоны

Вопрос:

Предположим, у нас есть operator/ пользовательский класс on:

 struct my_class {
    uint64_t value;
}

template<class T>
constexpr T operator/(const my_classamp; a, const my_classamp; b)
{
    return static_cast<T>(a.value) / static_cast<T>(b.value);
}
  

Как можно выбрать a / b (где a и b имеют my_class тип) для возврата int или double , например?

Комментарии:

1. Выберите на основе чего?

2. изменить constexpr T operator/ на constexpr int operator/ ?

3. @appleapple Я хочу иногда получать double , а иногда получать int .

4. @VioletGiraffe Это действительно вопрос 🙂

5. std::enable_if и несколько определений / перегрузок для operator/ , как мне кажется.

Ответ №1:

Вы могли бы использовать немного магии шаблонов и операторов преобразования. Сначала вы можете определить простую оболочку для своего выражения:

 struct DivideMyClass {
    DivideMyClass(const MyClassamp; lhs_, const MyClassamp; rhs_) : lhs{lhs_}, rhs_{rhs} {}

    template<typename T>
    operator T () const {
        return static_cast<T>(lhs.value) / static_cast<T>(rhs.value);
    }

private:
    const MyClassamp; lhs;
    const MyClassamp; rhs;
};
  

Затем перегрузка оператора может быть выполнена следующим образом:

 constexpr DivideMyClass operator/(const my_classamp; a, const my_classamp; b)
{
    return DivideMyClass{a, b};
}
  

Тогда ваш код будет выглядеть следующим образом:

 double d = MyClass{21} / MyClass{5}; // will be equal to 4.2
  

Почему это решение плохое

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

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

Вы предотвратите idom AAA (почти всегда используйте Auto). auto может нарушить ваш код, и это плохо.

Подобные методы следует использовать для выражения шаблона и тому подобного. Использование этого для простого разделения приведет к путанице.

Комментарии:

1. Будет auto ли работать, если я напишу template <typename T = double> , например, в прокси-классе?

2. Нет. Auto не будет выполнять никаких преобразований. Auto выведет тип выражения, следующего за = .

Ответ №2:

Могу ли я выбирать на основе типа переменной, принимающей результат? Т.е. int result = a / b возвращает int, но double result = a / b возвращает double ?

Если вы одержимы этим, вы можете, но это сложно, и я бы не рекомендовал это. Вы должны тщательно взвесить преимущества и сложность. Вы можете сделать это с помощью отложенной оценки:

 struct X {
  int value;
};

struct X_op_proxy {
  const Xamp; lhs;
  const Xamp; rhs;

  template <class T>
  operator T() const { return static_cast<T>(lhs.value) / static_cast<T>(rhs.value); }
};
auto operator/(const Xamp; lhs, const Xamp; rhs) -> X_op_proxy
{
    return {lhs, rhs};
}

int main()
{
  X x1{11}, x2{2};

  int i = x1 / x2;
  cout << i << endl;

  float f = x1 / x2;
  cout << f << endl;
}
  

Это минимум, чтобы вы могли понять, что представляет собой этот метод. Вы можете адаптировать его и расширить в соответствии с вашими потребностями.

Комментарии:

1. Вау! Отлично! Я думал, что это невозможно 🙂 Вот почему я задаю здесь такие глупые (на первый взгляд) вопросы 🙂 Спасибо!

2. Почему не просто X_op_proxy operator/(const Xamp; lhs, const Xamp; rhs) ?

3. @W.F. Просто альтернативный синтаксис, не имеет значения.

4. болов, возможно ли это сделать для auto i = x1 / x2 возврата double (например) по умолчанию?

5. @vladon но я считаю, что использование шаблона по умолчанию или перегрузка оператора приведения не приведут к желаемому поведению

Ответ №3:

Чтобы выбрать конкретный шаблон оператора, вы должны вызвать его как функцию:

 auto result = operator/<double>(my_class{4}, my_class{2});
// result is 2.0
  

Комментарии:

1. Да, но это плохо. Могу ли я выбрать на основе типа переменной, принимающей результат? Т.е. int result = a/b Возвращает int , но double result = a/b возвращает double?

2. @vladon нет, вы не можете

3. @vladon что вы могли бы сделать, так это отложенную оценку с помощью прокси-класса. Но это слишком много работы