8

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;
}

ライブデモ

残念ながら、この累乗演算子の優先順位と結合性は間違っています。私の質問は次のとおりです。これを修正するにはどうすればよいですか?数学表記のように、 my<pow>をより優先して右に関連付けたいと思います。*

編集異なる括弧を使用して優先順位を変えること|op|/op/可能*op*です<<--op-->>。しかし、今日の C++ はテンプレート メタプログラミングと型推論で非常に強力であるため、目的の結果を達成するには別の方法が必要です。

powさらに、 and notを使用できればいいのにと思いますpwr。残念ながら、一部の実装ではグローバル名前空間に#include <cmath>持ち込むため、競合が発生します。フォームの宣言のようpowにオーバーロードできますかoperator not

not using std::pow;

std::powグローバル名前空間から削除されましたか?

さらに読む: Bjarne Stroustrup による関連する提案

4

1 に答える 1

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;

この式テンプレートが最適な時間よりも長く保存されるのを避けるには、単純にオーバーロードoperator auto()&&して推定型を返します。コンパイラがその機能をサポートしていない場合=equals=は、明確さを若干犠牲にして適切な型を返すことができます。

上記の構文は、OP と同様の手法を使用して C++ で実際に実現できることに注意してください。実際の実装は、SO 投稿に含める必要があるサイズよりも大きくなります。

他にも利点があります。誰もが知っているように、プログラミング言語のあいまいな ASCII 文字は支持されなくなり、C++ を読んでいる人は次のような表現で混乱する可能性があります。

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

この手法を使用すると、すべての演算子に意味を明確にする読み取り可能な名前が付けられ、すべてが中置表記と前置表記を混在させるのではなく、中置表記で行われます。

powが利用可能であることを確認するための同様のソリューションは<cmath><cmath_nopow>自分で再実装することで実行できます。これにより、AST 文法モナドが分離したり、標準に違反したりする、言語構造上ではない演算子のオーバーロードが回避されます。たぶんHaskellを試してみませんか?

于 2016-04-01T14:58:10.773 に答える