#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 что вы могли бы сделать, так это отложенную оценку с помощью прокси-класса. Но это слишком много работы