c++ - 用户定义的中缀运算符

标签 c++ c++14 user-defined infix-operator

在 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来自全局命名空间?

进一步阅读:a related proposal by Bjarne Stroustrup .

最佳答案

最小意外原则很重要,关键是 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=可以以适度的清晰度代价返回正确的类型。

请注意,上述语法实际上可以使用类似于 OP 的技术在 C++ 中实现。实际实现比 SO 帖子应该包含的要大。

还有其他好处。众所周知,晦涩难懂的 ASCII 字符在编程语言中已经失宠,阅读 C++ 的人可能会被这样的表达式搞糊涂:

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

使用这种技术,所有运算符都具有可读的名称,使其含义清晰,并且一切都在中缀而不是混合中缀和前缀表示法。

确保类似的解决方案pow可以通过重新实现 <cmath> 来完成作为<cmath_nopow>你自己。这避免了重载不在语言结构上的运算符,这会导致 AST 语法单子(monad)解耦,和/或违反标准。也许试试 Haskell?

关于c++ - 用户定义的中缀运算符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36356668/

相关文章:

c++ - 将 const 对象引用传递给仿函数

c++ - 为什么这段代码涉及使用对临时段错误的引用,尽管它似乎正确地管理了生命周期?

c++ - 在 O(n) 中搜索 std::map 以获取部分键

python - 是否可以在python中声明用户定义的语句(与assert的语法相同)?

c++ - 如何使用 QPainter 添加新对象?

c++ - 有什么好的 C 或 C++ 库可以处理大型点云吗?

c++ - 简单程序省略的第一个字符

C++ 多线程 TCP 服务器问题

java,两个二维数组及其交互,ArrayIndexOutOfBounds Exception

Java:根据用户定义的函数生成随机数