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

легко ввести новые операторы infix в 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;
}

Live demo

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

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

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

not using std::pow;

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

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

1 ответов


принцип наименьшего удивления важен, и это ключ, который 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++ с использованием методов, подобных OP. Фактическая реализация больше, чем должна содержать должность SO.

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

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

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

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