用户定义的中缀运算符 [英] User-defined infix operators
问题描述
很容易在C ++中引入新的中缀运算符
It is easy to introduce new infix operators in 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>
的优先级高于*
并与右侧关联,就像在数学符号中一样.
Unfortunately, this power operator has wrong precedence and associativity. So my question is: how to fix this? I want my <pow>
to have higher precedence than *
and associate to the right, just like in the mathematical notation.
编辑可以通过使用不同的方括号来更改优先级,例如|op|
,/op/
,*op*
或什至是倾斜的<<--op-->>
,但不能以这种方式高于最高的内置运算符优先级.但是如今,C ++在模板元编程和类型推断方面是如此强大,只需采用其他方法即可达到所需的结果.
Edit It is possible to vary the precedence by using different brackets, e.g. |op|
, /op/
, *op*
or even, if one is so inclined, <<--op-->>
, but one cannot go higher than the highest built-in operator precedence this way. But today C++ is so powerful with template metaprogramming and type deduction, there simply ought to be some other way to achieve the desired result.
此外,如果我可以使用pow
而不是pwr
会很好.不幸的是,在某些实现中,#include <cmath>
将pow
带入了全局名称空间,因此会发生冲突.我们可以重载operator not
这样的形式声明
Additionally, it would be nice if I could use pow
and not pwr
. Unfortunately in some implementations #include <cmath>
brings pow
into the global namespace, so there will be a conflict. Can we overload operator not
such that a declaration of the form
not using std::pow;
从全局名称空间中删除了std::pow
?
removed std::pow
from the global namespace?
进一步阅读:相关Bjarne Stroustrup的建议.
推荐答案
最小惊喜原则很重要,a*b *power* c * d
评估为a* (b^c) *d
是关键.幸运的是,有一个简单的解决方案.
The principle of least surprise is important, and it is key that a*b *power* c * d
evaluate to a* (b^c) *d
. Luckily there is an easy solution.
要确保*power*
的优先级高于乘法,则必须使用类似的命名运算符技术进行乘法.
To ensure that *power*
has a higher precedence than multiplication, you have to use a similar named operator technique for multiplication.
然后,您可以直接构建表达式树,而不是直接计算*power*
和*times*
的结果.评估后,该表达式树可以应用任意优先级规则.
Then instead of directly calculating the results of *power*
and *times*
, you instead build an expression tree. This expression tree, when evaluated, can apply arbitrary precedence rules.
我们可以对每个内置运算符执行此操作,从而使我们易于阅读的语法允许对运算符优先级进行编译时元编程:
We can do this with every built-in operator, giving us an easy to read syntax that permits compile-time metaprogramming of operator precedence:
auto z =equals= bracket<
a *plus* b *times* c *power* bracket<
a *plus* b
>bracket *power* x *times* y
>bracket;
为避免此表达式模板的存储时间超出最佳值,只需重载operator auto()&&
以返回推导的类型.如果您的编译器不支持该功能,则=equals=
可以以适当的代价返回正确的类型.
To avoid this expression template from being stored longer than optimal, simply overload operator auto()&&
to return the deduced type. If your compiler fails to support that feature, =equals=
can return the proper type at a mild cost of clarity.
请注意,上述语法实际上可以使用类似于OP的技术在C ++中实现.实际实现大于SO帖子应包含的内容.
Note that the above syntax is actually realizable in C++ using techniques similar to the OP's. An actual implementation is larger than a SO post should contain.
还有其他好处.众所周知,编程语言中晦涩难懂的ASCII字符已不受欢迎,并且阅读C ++的人们可能会被诸如以下的表达式所迷惑:
There are other benefits. As everyone knows, obscure ASCII characters in programming languages have fallen out of favor, and people reading C++ may be confuesed by expressions like:
int z = (a + b* pow(c,pow(x,a+b))*y);
使用这种技术,所有运算符都有可读的名称,可以清楚地说明其含义,并且所有操作都以infix完成,而不是混合使用infix和前缀表示法.
With this technique, all operators have readable names that make their meaning clear, and everything is done infix instead of mixing infix and prefix notation.
可以通过自己重新实现<cmath>
作为<cmath_nopow>
来实现确保pow
可用的类似解决方案.这避免了运算符不重载于语言结构上,从而导致AST语法单子解耦和/或违反标准.也许尝试Haskell?
Similar solutions to ensure that pow
is available can be done by reimplementing <cmath>
as <cmath_nopow>
yourself. This avoids overloading operator not on language constructs, which causes AST grammar monads to decouple, and/or violates the standard. Maybe try Haskell?
这篇关于用户定义的中缀运算符的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!