【问题标题】:Define operator ** in C++在 C++ 中定义运算符 **
【发布时间】:2013-11-07 01:27:54
【问题描述】:

我如何定义运算符 ** 以便它可以执行 2 个数字的幂运算。例如2 ** 3。答案应该是 8。

或者间接有什么方法可以通过运算符重载而不是#define 宏来做到这一点?

【问题讨论】:

标签: c++ operators operator-overloading


【解决方案1】:

你不能。您只能重载现有的运算符,而不能重载内置类型。

【讨论】:

  • 我想知道(因为我不知道)C++14 opaque typedefs 是否可以模拟内置类型以实现 OP 愿意实现的目标。
  • @PaperBirdMaster 文字数字将始终具有 int 类型。你也许可以使用用户定义的文字和东西,但像2**16 这样简单的东西永远不会起作用。
  • @n.m.我知道你对文字的看法(可能不仅仅是 int ;)但我只是想知道/幻想 opaque typedefs 以及它们是否可以用于像 OP 想要的东西:supertypedef int potatoes; 和免费运营商:potatoes operator *(const potatoe a, const potatoe b) { return std::pow(a, b); } 但现在我正在写它,这对我来说看起来很愚蠢
【解决方案2】:

你不能。您只能重载 C++ 中现有的运算符;您不能添加新的,或更改现有运算符的数量或关联性。甚至预处理器在这里也无能为力——它的标识符不能是符号。

【讨论】:

  • 当然,你可以使用named operator idiomgithub.com/klmr/named-operator定义新的
  • @sehe Mind:吹。我已经习惯了元编程之类的东西,但是这种运算符重载的使用甚至从未在我的脑海中出现过。我只为您的链接收藏了这些问题。
  • @sehe 这是一个很好的成语,我自己在 2005 年左右(重新)发现了它,但它无法定义具有正确优先级和关联性的幂运算符。
  • 是的。我只是为了开阔视野而提到它。快让我 +1 你的答案。好像忘记了
  • @poorva:实际上在书中它不是 1,而是 I(拉丁文大写字母)。这一切都不同。
【解决方案3】:

如果你愿意妥协 w.r.t. ** 并想混淆你的代码:

#include <cmath>
#include <iostream>

struct foo {
    foo(int i) : i_(i) {}
    int operator*(int exp)
    {
        return std::pow(i_,exp);
    }
private:
    int i_;
};

struct bar {
} power_of;

foo operator*(int i, bar)
{
    return foo{i};
}


int main()
{
    std::cout << 2 *power_of* 3;  // prints 8
}

否则,请使用std::pow

【讨论】:

  • 可以加#define $$ *power_of*,所以是2 $$ 3。另外,我会使用具有从右到左关联性的运算符,例如*=,所以4 $$ 3 $$ 2 的结果将是262144DEMO
【解决方案4】:

就像提到的其他答案一样,这对于内置类型是不可能的但是你可以让它适用于像这样的自定义类型(最小代码示例):

#include <cmath>
#include <iostream>

struct dummy;

struct Int
{
    int i;
    Int() : i(0) {}
    Int(const int& i) : i(i) {}
    dummy operator*();
};

struct dummy
{
    Int* p;
    dummy(Int* const p) : p(p) {}

    int& operator*()
    {
        return p->i;
    }
};

dummy Int::operator*()
{
    return dummy(this);
}

int operator*(const Int& lhs, const dummy& rhs)
{
    return std::pow(lhs.i, rhs.p->i);
}


int main()
{
    Int a(2);
    Int b(2);
    std::cout<< a ** b << std::endl; 
}

Live example

【讨论】:

  • @poorva:实际上看起来比我的版本更干净。不错!
【解决方案5】:

正如其他人所指出的那样:这是不可能的。您可以重载另一个运算符,例如 ^,用于求幂,但是可以在简单的类型包装类/对象上重载。

但是,如果您喜欢冒险,另一种方法是创建一个微型 DSL,以支持此类运算符的动态计算。 (A famous example of that is LISP in C++)

但是,考虑到所涉及的努力,它可能是也可能不是您的一杯茶。但是,值得知道这种可能性是存在的。

更新:

运算符重载通过重载已经存在的运算符来工作。为什么?因为如果您可以定义自己的,您还必须定义这些运算符的优先级,这些运算符很容易通过抽象出它们的原始目的而让位于滥用运算符 - 这增加了阅读代码的难度。 (至少这是已经提出的论点)。

语义最接近** 的运算符是插入符号运算符。这种操作符的一个简单和说明性的实现是:

#include <iostream>
#include <cmath>

class Int {
public:
    Int() {}
    Int(int i) : value(i) {}

    friend double operator^(const int& i, const Int& integer);
    friend double operator^(const Int& integer, const int& i);
    friend double operator^(const Int& lhs, const Int& rhs);
private:
    int value;
};

double operator^ (const int& lhs, const Int& rhs) {
    return std::pow(lhs, rhs.value);
}

double operator^ (const Int& lhs, const int& rhs) {
    return std::pow(lhs.value, rhs);
}

double operator^ (const Int& lhs, const Int& rhs) {
    return std::pow(lhs.value, rhs.value);
}


int main() {
    Int i1 = 10;
    Int i2 = 3;
    double result = i1 ^ i2;

    std::cout << result;
    return 0;
}

【讨论】:

  • 有什么方法可以让 2 ** 3 调用一个函数,比如说 mypow (int ,int); ?
  • 实际上在 Bjarne Stroustrup 的 C++ 编程语言中我遇到了这个问题 - 定义一个类索引来保存指数函数 mypow(double, index) 的索引。找到一种方法来拥有 2 ** 1 调用 mypow(2,1)
  • @poorva:正确。但是,我相信您错过了练习的重点:它是创建可以解析和执行计算的类,例如:2 ** 1。您可以使用运算符重载,但由于 C++ 不支持运算符重载来创建一个运算符,例如:** 本机(注意,我是本机说的),那么练习显然降级为使用对 C++ 的不同理解和应用来解决这个问题。提示是,它要么是一个解析问题,可以在编译时使用宏来完成,要么是在运行时使用类、对象和函数来完成。
  • operater_overloading 这可行,但这是正确的做法吗?
  • @poorva:有很多方法可以做到这一点,是否正确,取决于情况/上下文。可能适合你或我的东西,不一定适合其他人。如果它有效,并且您理解它:它的优点和缺点,那么这就是最重要的。
【解决方案6】:

不幸的是,可以在 C++ 中重载的运算符集是固定的,不包括 ** 运算符。您可能会考虑改用 operator^(),但事实证明 ^ 用作幂运算符的优先级错误。

简而言之,很遗憾,您对此无能为力。

【讨论】:

    【解决方案7】:

    您不能为内置类型重载运算符。对于自定义类型,我会使用 operator ^ 来实现此目的。

    【讨论】:

    • 我不会。一方面,它的优先级错误。对于两个,没有。只是没有。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-21
    • 2011-01-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多