Заставить все математические операторы структуры манипулировать одним и тем же элементом

#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;
}
  

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