Пользовательские инфиксные операторы

В C ++ легко вводить новые инфиксные операторы

// User-defined infix operator framework

template <typename LeftOperand, typename Operation>
struct LeftHelper
{
const LeftOperand& leftOperand;
const Operation& operation;
LeftHelper(const LeftOperand& leftOperand,
const Operation& operation)
: leftOperand(leftOperand), operation(operation) {}
};

template <typename LeftOperand, typename Operation >
auto operator < (const LeftOperand& leftOperand,
Operation& operation)
{
return LeftHelper<LeftOperand, Operation>(leftOperand, operation);
}

template <typename LeftOperand, typename Operation, typename RightOperand>
auto operator > (LeftHelper<LeftOperand, Operation> leftHelper,
const RightOperand& rightOperand)
{
return leftHelper.operation(leftHelper.leftOperand, rightOperand);
}

// Defining a new operator

#include <cmath>
static auto pwr = [](const auto& operand1, const auto& operand2) { return std::pow(operand1, operand2); };

// using it
#include <iostream>
int main()
{
std::cout << (2 <pwr> 16) << std::endl;
return 0;
}

Живая демо

К сожалению, этот степенной оператор имеет неправильный приоритет и ассоциативность. Итак, мой вопрос: как это исправить? Я хочу мое <pow> иметь более высокий приоритет, чем * и ассоциировать справа, как в математической записи.

редактировать Можно изменить приоритет, используя разные скобки, например, |op|, /op/, *op* или даже, если кто-то так склонен, <<--op-->>, но таким образом нельзя превысить наивысший приоритет встроенного оператора. Но сегодня C ++ настолько мощен с метапрограммированием шаблонов и выводом типов, что просто должен быть какой-то другой способ достичь желаемого результата.

Кроме того, было бы неплохо, если бы я мог использовать pow и не pwr, К сожалению, в некоторых реализациях #include <cmath> приносит pow в глобальное пространство имен, поэтому будет конфликт. Можем ли мы перегрузить operator not такой, что декларация формы

not using std::pow;

удален std::pow из глобального пространства имен?

Дальнейшее чтение: соответствующее предложение Бьярне Страуструпа.

8

Решение

Принцип наименьшего удивления важен, и это ключ, который a*b *power* c * d оценить a* (b^c) *d, К счастью, есть простое решение.

Чтобы убедиться, что *power* имеет более высокий приоритет, чем умножение, для умножения вы должны использовать похожий метод именованных операторов.

Тогда вместо непосредственного расчета результатов *power* а также *times*вместо этого вы строите дерево выражений. Это дерево выражений при оценке может применяться произвольные правила приоритета.

Мы можем сделать это с каждым встроенным оператором, что дает нам простой для чтения синтаксис, который позволяет во время компиляции метапрограммировать приоритет оператора:

auto z =equals= bracket<
a *plus* b *times* c *power* bracket<
a *plus* b
>bracket *power* x *times* y
>bracket;

Чтобы этот шаблон выражения не хранился дольше оптимального, просто перегрузите operator auto()&& вернуть выведенный тип. Если ваш компилятор не поддерживает эту функцию, =equals= может вернуть правильный тип с умеренной ценой ясности.

Обратите внимание, что приведенный выше синтаксис на самом деле реализуется в C ++ с использованием методов, аналогичных операциям. Фактическая реализация больше, чем должна содержать публикация SO.

Есть и другие преимущества. Как всем известно, непонятные символы ASCII в языках программирования перестали нравиться, и люди, читающие C ++, могут быть убеждены такими выражениями, как:

int z = (a + b* pow(c,pow(x,a+b))*y);

С помощью этой техники все операторы имеют читаемые имена, которые проясняют их значение, и все делается инфиксно, а не смешивает инфиксную и префиксную нотацию.

Подобные решения, чтобы гарантировать, что pow доступно может быть сделано путем переопределения <cmath> как <cmath_nopow> сам. Это позволяет избежать перегрузки оператора не в языковых конструкциях, что приводит к разделению грамматических монад AST и / или нарушению стандарта. Может быть, попробуйте Haskell?

6

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]