#c #struct #operators
#c #структура #операторы
Вопрос:
У меня есть структура, содержащая double и несколько флагов, но я хотел бы использовать ее в своем коде, как если бы это был просто double . Есть ли способ упростить следующий код, чтобы все математические операторы, выполняемые на экземпляре этой структуры, выполнялись на содержащем double ? Мой код выполняется, но я подозреваю, что у C есть очень элегантное и короткое решение моей проблемы.
struct SomeStruct
{
double value;
bool someFlag;
bool someOtherFlag;
operator double(){return value;}
void operator=(double newValue){value = newValue;}
void operator =(double valueToAdd){value = valueToAdd;}
void operator-=(double valueToSubtract){value-= valueToSubtract;}
void operator/=(double divisor){value /= divisor;}
void operator*=(double multiplier){value *= multiplier;}
double operator (double valueToAdd){return value valueToAdd;}
...
}
Комментарии:
1. Ваш оператор преобразования позволит это сделать без перегрузок оператора.
2. Возможно, Boost . Operators решает вашу проблему.
3. Если это даже компилируется, оно не делает того, что вы думаете. Ваш
struct
не содержит элемента с именемvalue
, поэтому все ссылки на него будут ссылаться на глобальную переменную с именемvalue
или что-то в этом роде, и только один из этих операторов, похожеstruct
, вообще изменяет ваш, что очень странно для семантики оператора…4. Какова ваша структура? Почему вы хотите это сделать?
5. Нет, я могу понять, что все еще используется в ваших вычислениях, но, как вы это разработали, если у нас есть два образца
A
иB
иA
перегружен, ноB
нет, тогдаA = B
перегружен, ноB = A
нет. Это тревожное поведение. Я бы сказал, что вы должны писать свои собственные функции и в каждом случае копировать наихудший случай перегруженного флага.
Ответ №1:
Если вы измените оператор преобразования на operator double amp;
, вы получите все операторы double
бесплатно, за исключением operator=
:
#include <iostream>
struct Foo {
double d;
bool flag;
Foo() : d(0), flag(false) {}
operator double amp;() { return d; }
};
int main()
{
Foo x; // initialized to (0, false)
x.flag = true;
x = 1.1;
std::cout << x.d << " " << x.flag << std::endl;
x *= 2;
std::cout << x.d << " " << x.flag << std::endl;
}
С принтами
1.1 1
2.2 1
(второй вывод — это flag
).
Возможно, все же стоит также определить operator double() const
.
Комментарии:
1. Не требуется для ответа на вопрос, но я бы
const
тоже добавил перегрузку.2. Возможно, я упускаю что-то очевидное, но какое правило в стандарте гласит, что
x
оно будет инициализировано(0, false)
(в отличие от неопределенного значения)?3. @T.C.: извините, добавил явный конструктор.
4. Я настоятельно рекомендую вам этого не делать. Неявные преобразования этого типа — это случайность, ожидающая своего часа. Вы думаете, что ведете себя умно, и какое-то время это прекрасно работает, но в конце концов это превращается в кроличью нору, в которую вы не хотите спускаться.
5. @JackAidley Не могли бы вы привести пример того, что может пойти не так?
Ответ №2:
Чтобы превратить наше обсуждение в комментариях в ответ…
Я не думаю, что вам вообще следует это делать. Как вы упомянули в комментариях, ваша структура содержит информацию из акустического измерения, так что она имеет как значение, так и флаг, указывающий, перегрузило ли измерение шума записывающий прибор. Позвольте мне упростить вашу структуру до этого:
struct Noise
{
double noiseLevel;
bool overload;
};
Теперь предположим, что вы добавили оператор преобразования, чтобы получить простоту и удобство, которые он предлагает. Теперь у вас есть два измерения шума quiet
и loud
. loud
установлен флаг перегрузки, в то время quiet
как нет. Теперь вы можете выполнить эти две операции, которые читатель должен ожидать, чтобы получить одинаковый результат:
loud = quiet;
и
quiet = loud;
но поскольку ваше добавление не учитывает флаг, две операции приводят к разным значениям. В первом случае overload
флаг установлен, а во втором — нет. Мне кажется, это очень тревожное поведение. Поэтому вместо этого я рекомендую вам реализовать свои собственные операторы, учитывающие типы, которые overlaud
естественным образом сохраняют флаг, например
Noiseamp; operator =(Noiseamp; lhs, const Noiseamp; rhs)
{
lhs.value = rhs.value;
lhs.overload |= rhs.overload;
return lhs;
}
Так что результат любого вычисления, в котором у одного элемента установлен флаг перегрузки, также имеет установленный флаг перегрузки.