在C++中,定义运算符**是什么意思?

9

如何定义运算符**,使其能够对两个数字进行指数运算。例如2 ** 3。它应该给出8作为答案。

或者间接地说,我是否可以通过运算符重载来实现这一点,而不是使用#define宏?


1
http://www.stroustrup.com/bs_faq2.html#overload-operator - Evgeny Panasyuk
只需使用pow - Inverse
7个回答

19

你不能这样做。你只能重载现有的运算符,而不能针对内置类型进行操作。


我不确定(因为我不知道)C++14的“opaque typedef”是否可以模拟内置类型以实现OP想要实现的目标。 - PaperBirdMaster
@PaperBirdMaster 字面常数始终具有“int”类型。你可能能够使用用户定义的字面量之类的东西,但像“2 ** 16”这样的简单操作永远不会起作用。 - n. m.
@n.m. 我知道你所说的字面值(可能不仅仅是int ;),但我只是在想象关于“opaque typedef”的事情,以及它们是否可以用于像OP想要的那样:supertypedef int potatoes; 和一个自由运算符:potatoes operator *(const potatoe a, const potatoe b) { return std::pow(a, b); } 但现在当我写下来时,它看起来甚至对我自己都很愚蠢。 - PaperBirdMaster

10

你不能。在C++中,只能重载现有的运算符,无法添加新的运算符或更改现有运算符的参数个数或结合性。即使是预处理器在这里也无能为力——它的标识符不能成为符号。


10
当然,你可以使用命名运算符惯用法来定义新的操作符。参见:https://github.com/klmr/named-operator - sehe
1
@sehe 惊呆了。我习惯于元编程等技术,但是这种运算符重载的用法从未在我的脑海中出现过。我会收藏这个问题,就为了你提供的链接。 - Angew is no longer proud of SO
@sehe 这是一个不错的习惯用语,我自己在2005年左右重新发现了它,但它无法正确定义幂运算符的优先级和结合性。 - n. m.
没错。我只是为了开阔视野而提到它。快让我给你的答案点个赞。看来我忘记了。 - sehe
实际上,在Bjarne Stroustrup的C++编程语言中,我遇到了这个问题 - 定义一个类Index来保存指数函数mypow(double,index)的索引。找到一种方法使2 ** 1调用mypow(2,1)。 - poorva
2
@poorva:实际上在书中不是数字1,而是拉丁大写字母I。这使得区别很大。 - n. m.

5
如果你愿意妥协于 ** 并且想让你的代码更加混淆:
#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 的结果将是 262144演示 - Evgeny Panasyuk

5

正如其他答案所指出的,对于内置类型来说这是不可能的但是你可以按照以下方式使自定义类型实现此功能(最小代码示例):

#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:那看起来比我的版本更简洁。干得好! - user1233963

3
正如其他人指出的那样:这是不可能的。你可以重载另一个运算符,比如幂运算的 ^,但只能在一个简单类型包装类/对象上进行。

但是,如果你想冒险的话,另一种方法是创建一个微型 DSL,支持即时计算此类运算符。 (这方面的著名例子是 C++中的 LISP)

然而,考虑到所涉及的工作量,这可能或可能不是你喜欢的。不过,值得知道这样的可能性是存在的。

更新:

运算符重载通过重载已经存在的运算符来实现。为什么?因为如果你可以定义自己的运算符,你也将不得不定义这些运算符的优先级,这很容易引起滥用运算符并使它们抽象化 - 这增加了读取代码的难度。(至少这是已经提出的论点)。

最接近具有与 ** 语义相关的运算符是插入符号运算符。这种运算符的一种天真而富有表现力的实现方式是:

#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)? - poorva
@poorva:没错。但是我认为你忽略了这个练习的重点:它是要创建一个类,可以解析和执行像2 ** 1这样的计算。你可以使用运算符重载,但是由于C++本身不支持像**这样的运算符重载(注意,我说的是本地支持),那么这个练习显然就需要利用C++的不同理解和应用来解决这个问题。提示是它可能是一个在编译时可以用宏完成的解析问题,或者是在运行时可以用类、对象和函数完成的解析问题。 - jrd1
1
运算符重载 这个可以工作,但这是正确的做法吗? - poorva
@jrd1:它绝对不是“唯一重要的事情”。为什么你不曾考虑过你的同事,无论是现在还是将来? - Lightness Races in Orbit
@LightnessRacesinOrbit:“我无法创造我不知道的东西。” 如果OP不知道他使用的是什么,他就不能创造。 因此,他必须理解它。 这就是我所做的,也是每个人都会做的(在某个时候或另一个时候)。 我没有忽视任何人。 不,一点也不。 如果有什么,你必须能够理解某些事物,然后才能向别人表达这种思想,意识形态和相关的孕育。 我的帖子就是这样的。 :) - jrd1
显示剩余4条评论

0
你不能重载内置类型的运算符。我会为自定义类型使用 operator ^ 来实现这样的目的。

1
我不会这么做。首先,它的优先级是错误的。其次,不行,绝对不行。 - Xeo

0

不幸的是,在C++中可以重载的运算符集是固定的,不包括**运算符。您可能会考虑使用operator^()代替,但事实证明^的优先级不正确,无法用作指数运算符。

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接