我可以用C++创建一个新的运算符吗?

sha*_*ing 34 c++

MATLAB数组支持矩阵运算和元素运算.例如,M*NM.*N.这是区分两种不同操作的非常直观的方式.如果我想在C++中实现类似的操作,我该怎么做?

我也可以创建一个新的运营商.*吗?如果是的话,有人可以给我一些指导吗?

Lig*_*ica 27

不,你不能超载op.*:

[C++03 & C++11: 13.5/3]: 以下运算符不能重载:

. .* :: ?:
Run Code Online (Sandbox Code Playgroud)

  • @FrancisCugler:没有人忘记他们; 该约束(可能)在标准的其他地方列出.我简单地引用了单一段落,声明"op.*"不能超载,因为那是OP所要求的. (3认同)
  • 不要忘记包含`sizeof()`和`typeid()` (2认同)

lor*_*rro 16

在C++中,有一个预定义运算符列表,其中大多数是可重载的(.*不是).此外,任何名称都可以用作运算符,如:

#include <iostream>

// generic LHSlt holder
template<typename LHS, typename OP>
struct LHSlt {
    LHS lhs_;
};

// declare myop as an operator-like construct
enum { myop };

// parse 'lhs <myop' into LHSlt
template<typename LHS>
LHSlt<LHS, decltype(myop)> operator<(const LHS& lhs, decltype(myop))
{
    return { lhs };
}

// declare (int <myop> int) -> int
int operator>(LHSlt<int, decltype(myop)> lhsof, int rhs)
{
    int& lhs = lhsof.lhs_;
    // here comes your actual implementation
    return (lhs + rhs) * (lhs - rhs);
}

// strictly optional
#define MYOP <myop>

int main() {
    std::cout << (5 <myop> 2) << ' ' << (5 MYOP 2);
}
Run Code Online (Sandbox Code Playgroud)

免责声明:严格地说,被翻译成(5 < myop) > 2,这是LHSlt<int, decltype(myop)>(5) > 2.因此,它不是一个新的"运算符",用C++术语来说,但它的使用方式完全相同,即使在ADL方面也是如此.此外,如果类型很大,您可能想要存储const T&.

请注意,您可以使用可在类外部定义的任何二元运算符执行此操作; 优先级基于双方(<>)的优先级.因此,你可以有例如*myop*,+myop+,<<myop>>,<myop>,|myop|在优先顺序.

如果你想要正确的关联性,它会变得有点棘手.你需要一个既RHS持有者和LHS-持有人(后者是LHSlt在这里),并利用周围的运营商使得右一个具有比左一个更高的优先级,例如a |myop> b |myop>ca |myop> (b |myop> c).然后你需要你的类型和持有者类型的函数作为lhs.

  • 这可能是最接近赏金的目的.遗憾的是,有人在寻找与原始问题不同的东西. (3认同)

Bar*_*rry 12

你不能超载.*(参见Lightness对标准文本的回答),但是,有趣的是,你可以重载->*(类似于你可以如何重载->而不是.).如果这足以区分,那就得到:

struct Int {
    int i;

    Int operator*(Int rhs) const { return Int{i * rhs.i}; }
    Int operator->*(Int rhs) const { return Int{i + rhs.i}; }

    friend std::ostream& operator<<(std::ostream& os, Int rhs) {
        return os << "Int(" << rhs.i << ')';
    }
};

int main() {
    Int five{5};
    Int six{6};

    std::cout << (five * six) << ", " << (five ->* six) << '\n';
}
Run Code Online (Sandbox Code Playgroud)

那打印Int(30), Int(11).


Fra*_*ler 7

MATLAB数组支持矩阵运算和元素运算.例如,M*N和M.*N. 这是区分两种不同操作的非常直观的方式.如果我想在C++中实现类似的操作,我该怎么做?

我可以创建一个新的运算符吗?*?如果是的话,有人可以给我一些指导吗?

至于第一部分,你可以重载大多数运算符,有些你不能重载,C++中的运算符列表是:

  • 算术

    • + (addition)
    • - (subtraction)
    • * (multiplication)
    • / (division)
    • % (modulus)
  • 按位

    • ^ (XOR)
    • | (OR)
    • & (AND)
    • ~ (Complement)
    • << (Shift Left, Insertion to Stream)
    • >> (Shift Right, Extraction from Stream)
  • 分配

    • = (Assignment)
  • 相关的

    • == (Equality)
    • != (Inequality)
    • > (Greater-Than)
    • < (Less-Than)
    • >= (Greater-Than Or Equal-To)
    • <= (Less-Than Or Equal-To)
  • 合乎逻辑

    • ! (NOT)
    • && (AND)
    • || (OR)
  • 复合赋值

    • += (Addition-Assignment)
    • -= (Subtraction-Assignment)
    • *= (Multiplication-Assignment)
    • /= (Division-Assignment)
    • %= (Modulus-Assignment)
    • &= (AND-Assignment)
    • |= (OR-Assignment)
    • ^= (XOR-Assignment)
    • <<= (Shift-Left Assignment)
    • >>= (Shift-Right Assignment)
  • 增量 - 减少 - 两者都有2种形式(前缀)和(后缀)

    • ++ (Increment)
    • -- (Decrement)
    • [] (Subscript)
  • 功能调用

    • () (Function Call)
  • 地址,参考,指针

    • operator&()
    • operator*()
    • operator->()
  • 逗号

    • operator,()
  • 会员参考

    • operator->()
    • operator->*()
  • 内存管理

    • new
    • delete
    • new[]
    • delete[]
  • 转变

    • operator "type" () const
  • 不可修改的运算符 - 不能超载的运算符

    • ?: (Conditional - Ternary)
    • . (Member Selection)
    • .* (Member Selection With Pointer To Member)
    • :: (Scope Resolution)
    • sizeof() (Object Size Information)
    • typeid() (Object Type Information)

因此,了解此列表将有助于回答您的问题.你能用C++创建一个"新运算符"吗?没有!如果要在C++中实现类似的操作; 我怎样才能做到这一点?

您有4个选择:重载已经存在的可以重载的操作符,编写一个函数或方法来执行您想要执行的计算类型,创建一个模板类型来为您完成工作,或者最后一个是最不常见但你也可以写宏来为你做这些.

有一个标题只有数学API库,经常与OpenGL图形API和OpenGL的着色器语言GLSL一起使用,这个库有许多功能,可以使用向量,矩阵,四元数等,以及可以完成的所有必要的功能和操作给他们.以下是GLM的链接您可以查看他们的文档以及他们的库实现,因为它只是一个头文件库或API.这应该可以让您深入了解它们如何构造Vector和Matrix对象以及可以对它们执行的操作.

  • @noɥʇʎԀʎzɐɹƆ:不,不是.那些技术(这个答案描述了它们!)只有_emulate_创建一个新的运算符. (2认同)

mat*_*ias 5

不,遗憾的是,您无法定义新的运算符 - 您只能重载现有的运算符(有一些重要的例外,例如operator.).即便如此,对于给定运算符具有非常清晰且无争议的现有语义的类型,重载运算符通常也是一个好主意 - 例如,任何表示为数字的类型都是重载算术和比较运算符的良好候选者,但是你应该确保operator+不减去两个数字.

  • @shangping matlab不使用C++作为其接口.matlab定义了自己的语言. (8认同)
  • @shangping你是对的,matlab是用另一种编程语言实现的*,甚至可能是C++,也可能是汇编语言.但是当你在matlab中定义一个新的运算符时,它不必直接对应于实现语言中的运算符; 例如,它可以编写一个C++函数,它知道在调用该运算符时调用它,或者它可以编写一个程序集块,它会导致处理器在调用运算符时跳转到.这是所有实施细节.你可以编写带有两个args的C++函数,而不是运算符. (3认同)
  • Matlab与C++无关. (2认同)

Pet*_*ter 5

顺便说一句:我正在寻求回答这个问题所提出的部分内容。我也不打算在其他有价值的答案中复制所有信息。赏金寻求与所提出的问题不同的东西,所以我不会对此做出回应。

提供矩阵乘法实际上相当简单。由于我不建议描述数据结构来表示矩阵并完全实现它们的操作和有效性检查,因此我将仅提供框架来说明。

示例1: operator*()作为成员函数

class M   // a basic matrix class
{
    public:

          // assume other constructors and members to set things up
       M operator*(const M &rhs) const;
};

M M::operator*(const M &rhs) const
{
       //   implement checks on dimensions, throw an exception if invalid

       M result;
        //  implement the multiplication (typical iterations) and store results in result
       return result;
}

int main()
{
     M a;
     M b;
        // set up elements of a and b as needed
     M c = a*b;    // this relies on M having appropriate constructor(s) to copy or move the result of a*b into c

     M d;
     d = a * b;    //  this relies on M having appropriate operator=() to assign d to the result of a*b
}
Run Code Online (Sandbox Code Playgroud)

上面operator*()作为成员函数实现。因此,从功能上来说,c = a*b相当于c = a.operator*(b). 限定符表示矩阵乘法通常不会改变或 的const事实。a*bab

示例 2: operator*()作为非成员函数

现在,operator*()也可以作为非成员(可选friend)实现,其骨架如下

class M   // our basic matrix class, different operator *
{
    public:

          // assume other constructors and members to set things up
       friend M operator*(const M &lhs, const M &rhs);
};

M operator*(const M &lhs, const M &rhs)
{
       //   implement checks on dimensions, throw an exception if invalid

       M result;
        //  implement the multiplication (typical iterations) and store results in result
       return result;
}

//   same main() as before
Run Code Online (Sandbox Code Playgroud)

请注意,在这种情况下,a*b现在相当于operator*(a, b).

如果您想使用这两种形式,则需要小心避免歧义。如果提供了两种形式,operator*()则它们在类似语句中都是有效匹配c = a*b,并且编译器无法选择一种形式而不是另一种形式。结果是代码无法编译。

示例 3:重载operator*()

也可以重载operator*()- 例如,将矩阵乘以标量。

class M   // a basic matrix class
{
    public:

          // assume other constructors and members to set things up
       M operator*(const M &rhs) const;    // as in first example

       M operator*(double scalar) const;    // member form
       friend M operator*(double scalar, const M &rhs);   // non-member form
};

M M::operator*(double scalar) const
{
       M result;
        //  implement the multiplication (typical iterations) and store results in result
       return result;
}

M operator*(double scalar, const M &m)
{
       M result;
        //  implement the multiplication (typical iterations) and store results in result
       return result;
}

int main()
{
     M a;
     M b;
        // set up elements of a and b as needed
     M c = b * 2.0;    // uses the member form of operator*() above

     M d;
     d = 2.0*a;        //  uses the non-member form of operator*() above
}
Run Code Online (Sandbox Code Playgroud)

上面b*2.0相当于对非会员的呼叫b.operator*(2.0)2.0*a对非会员的呼叫operator*(2.0, a)。成员形式通常只能用在左侧操作数类型为 的表达式中M。因此,如果仅提供2.0*a成员形式,则不起作用。operator*()

讨论

除了上面的歧义问题之外,重载运算符时还需要注意其他事项。

  • 无法根据语言规则中的规范更改运算符的优先级或结合性。因此,在表达式 中a+b*c*will 的优先级始终高于+^这也是在 C++ 中重载求幂不是一个好主意的原因,因为^它的优先级比 C++ 低+(是整数类型的按位运算)。Soa + b^c在 C++ 中实际上相当于(a + b)^c,而不是a + (b^c)(任何具有代数基础知识的人都会期望)。
  • 该语言指定了一组运算符,并且不可能创建新的运算符。例如,C++ 中没有**这样的a ** b幂(其他语言可以a做到b ),并且不可能创建一个。
  • 并非所有运算符都可以重载。

C++ 中不能重载的运算符之一是.*。所以不可能像在 Matlab 中那样使用这样的运算符。我通常建议不要尝试使用其他运算符获得相同的效果,因为上述约束会影响它(并导致表达式给出反直觉的行为)。相反,只需提供另一个命名函数来完成这项工作。例如,作为成员函数

   class M
   {
       public:
         // other stuff

          M ElementWiseProduct(const M &) const;
   };
Run Code Online (Sandbox Code Playgroud)