Пользовательские операторы 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;
}
к сожалению, этот оператор питания имеет неправильный приоритет и ассоциативность. Поэтому мой вопрос:как это исправить? я хочу, чтобы мои <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 и/или нарушает стандарт. Может быть, попробовать Хаскелла?