用户定义的中缀运算符 [英] User-defined infix operators

查看:128
本文介绍了用户定义的中缀运算符的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

很容易在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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆