用户定义的中缀运算符

n. *_* m. 8 c++ user-defined infix-operator c++14

在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;
}
Run Code Online (Sandbox Code Playgroud)

现场演示

不幸的是,这个幂运算符具有错误的优先级和相关性.所以我的问题是:如何解决这个问题?我希望我的<pow>优先级高于*右侧,并且与右侧相关联,就像在数学符号中一样.

编辑有可能通过使用不同的支架,如改变优先级|op|,/op/,*op*甚至,如果有一个这样的倾向,<<--op-->>但一个不能去比最高内置的运算符优先级这样高.但是今天C++在模板元编程和类型推导方面是如此强大,只需要一些其他方法来实现所需的结果.

另外,如果我可以使用pow而不是,那将是很好的pwr.不幸的是,在某些实现中#include <cmath>pow引入全局命名空间,因此会出现冲突.我们可以重载operator not这样的声明形式

not using std::pow;
Run Code Online (Sandbox Code Playgroud)

std::pow从全局命名空间中删除?

进一步阅读:Bjarne Stroustrup的相关提案.

Yak*_*ont 6

最不突然的原则很重要,它是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;
Run Code Online (Sandbox Code Playgroud)

为避免此表达式模板的存储时间超过最佳值,只需重载operator auto()&&以返回推导出的类型.如果您的编译器无法支持该功能,则=equals=可以以较低的清晰度成本返回正确的类型.

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

还有其他好处.众所周知,编程语言中隐藏的ASCII字符已经失宠,阅读C++的人可能会被以下表达式所困扰:

int z = (a + b* pow(c,pow(x,a+b))*y);
Run Code Online (Sandbox Code Playgroud)

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

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